Как сопоставить отношение «один ко многим» с моделью JSON в Slick - PullRequest
0 голосов
/ 03 июля 2018

У меня есть 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, они также имеют дублирующиеся значения. Кто-нибудь может предложить способ сопоставления или лучший способ извлечения данных из БД с примером.

извините, если я допустил какие-либо ошибки, я новичок в игровой структуре, и спасибо заранее.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Чтобы получить желаемый JSON, вам нужно отобразить результат в соответствующий класс дела.

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

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

Сопоставление с этим классом дел может быть выполнено в DBIOAction. Сначала группируйте результаты по идентификатору сотрудника, а затем сопоставьте все записи карты (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)
0 голосов
/ 05 июля 2018

То, что вы ищете, groupBy, я думаю.

Вы извлекаете данные по запросу присоединения и groupBy по идентификатору сотрудника.

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))

Сейчас

, где employee - это TableQuery объект employee, а report - TableQuery объект report.

Дай попробовать :)

...