如何在Slick中将一对多关系映射到JSON模型

时间:2018-07-03 17:16:31

标签: json scala playframework slick

我有2个这样的班

case class Employee(id: Long,
                    name: String,
                    prefix: Option[String],
                    role: String)

case class Report(id: Long,
                  name: String,
                  employee_id: Long)

期望JSON格式

{
   "id":1,
   "name":"employee",
   "prefix":"emp",
   "role":"eng",
   "reports":[
      {
         "id":1,
         "name":"report_1"
      },
      {
         "id":2,
         "name":"report_2"
      }
   ]
}

一个员工可以有许多报告(一对多),而我的表与外键连接,我的问题是这样从数据库中检索数据的方式我尝试了这种内部联接

val query: PostgresProfile.api.type#TableQuery[T]

  def getAllQuery = {
    query.filter(_.isDeleted === false)
  }

================================================

  def getAllEmployee: Future[Seq[Employee]] = {
    val joinQuery = super.getAllQuery.join(reportRepo.getAllQuery).on(_.id === _.employee_id)
    val joinRes: Future[Seq[(Employee, Report)]] = db.run(joinQuery.result)
    joinRes map { tupleList =>
      tupleList.map { tuple =>
        Employee(tuple._1.id, tuple._1.name, tuple._1.prefix, tuple._1.role)
      }
    }
  }

我收到了数据,当我尝试映射到JSON时,它也带有重复的值。任何人都可以通过示例来建议映射方式或从DB检索数据的更好方法。

对不起,如果我有任何错误,我是Playframework的新手,谢谢。

2 个答案:

答案 0 :(得分:0)

我想您正在寻找的东西是groupBy

您可以通过加入查询并根据员工的ID分组来获取数据。

val query = employee.filter(_.yourField === yourCondition).join(report).on(_.id === _.employee_id)

val joinRes = db.run(query.to[List].result)

joinRes.map { list =>
  list.groupBy {
    case (emp, report) => emp.id
  }
}

 joinRes.map(_.groupBy(_._1.id))

现在

其中employeeTableQuery的{​​{1}}对象,而employeereport的{​​{1}}对象。

尝试一下:)

答案 1 :(得分:0)

要获取所需的json,您需要将结果映射到适当的case类中。

  case class EmployeeWithReports(id: Long,
                                 name: String,
                                 prefix: Option[String],
                                 role: String, 
                                 reports: List[Report])

object EmployeeWithReports {
    implicit val jsonFormat = Json.format[EmployeeWithReports]
}

可以在DBIOAction中完成对此案例类的映射。首先,将结果按员工ID分组,然后将所有地图条目(Int, Seq[Employee, Report])映射到EmployeeWithReports

val query = super.getAllQuery
                .join(reportRepo.getAllQuery)
                .on(_.id === _.employee_id)

val action = query.result.map(rows => {
      rows.groupBy(_._1.id).map { mapEntry =>
        val (id, name, prefix, role) = mapEntry._2.head._1
        EmployeeWithReports(id, name, prefix, role, mapEntry._2.flatMap(_._2).toList)
      }.toList
    })

然后您可以得到结果调用

val employees: Future[List[EmployeeWithReports]] = db.run(action)