为连接查询的结果实现隐式写入

时间:2016-02-11 15:34:49

标签: scala playframework playframework-2.0 slick

编译错误:

No Json serializer found for type Seq[(models.Account, models.Company)]. Try to implement an implicit Writes or Format for this type.

如何为连接查询的结果定义隐式写入?

控制器:

def someEndpoint = Action.async { implicit request =>
    val query = for {
        a <- accounts if a.id === 10
        c <- companies if a.companyID === c.id
    } yield (a, c)
    db.run(query.result).map(rows => Ok(Json.toJson(rows)))  // Causes compilation error
}

我的每个模特(账户和公司)都有自己的隐式写作(这里是公司的一个):

case class Company(id: Int, name: String)

object Company {
  implicit val writes = new Writes[Company] {
    def writes(company: Company): JsValue = {
      Json.obj(
        "id" -> company.id,
        "name" -> company.name
      )
    }
  }
}

是否可以动态处理连接的序列化?我有很多事情要加入......我是否需要为每个组合明确定义writes

2 个答案:

答案 0 :(得分:1)

Writes.seq会帮助您

小作家

val w = (
  (__ \ "account").write[Account] and 
  (__ \ "company").write[Company]
).tupled

可帮助您使用

Seq[(models.Account, models.Company)]转换为JsValue
Writes.seq(w).writes(rows)

和最后一个命令将是

db.run(query.result).map(rows => Ok(Writes.seq(w).writes(rows))

或更明确的变体

db.run(query.result)
  .map(
    _.map{
      case (a,c) => Json.obj("account" -> a, "company" -> c)
    }
  )
  .map(rows => 
    Ok(JsArray(rows))
  )

它是一样的,但你自己为每一行创建了对象。

答案 1 :(得分:0)

我认为您希望JSON中的查询响应类似于

[
  {
    "account" : { "number": "123", "companyID" : 1 },
    "company" : { "id" : 1, "name" : "My company"}
  } , ...
]

问题是查询的响应只是一个元组,所以&#34; account&#34;和&#34;公司&#34;不容易计算。

您可以使用已连接的数据创建新的案例类,而不是元组,但我知道您希望避免这种情况。在这种情况下,你可以使用一个可以自动转换为JSON的Map来代替元组。

额外:为案例类创建编写器非常简单

import play.api.libs.json._
implicit val personWrites = Json.writes[Person]

参考:https://www.playframework.com/documentation/2.4.x/ScalaJsonInception