1

私はこの2つのテーブルを持っています:

    select * from "DEPARTMENTS";
 ID | NAME  | MANAGER_ID 
----+-------+------------
  1 | FOO   |          1
  3 | XXX   |          2
  4 | dept1 |           
(3 rows)

select * from "EMPLOYEES";
 NAME | LAST |      EMAIL       | PHONE | SKYPE | DEPT_ID | ID 
------+------+------------------+-------+-------+---------+----
 AAA  | xxxx | abcdef@gmail.com |       |       |         |  1
 BBB  | yyyy |                  |       |       |         |  2
(2 rows)

マネージャーの名前 (マネージャーが存在する場合) の合計 3 行のすべての部門を取得したい。

ただし、スキーマでは次のようにします。

import scala.slick.driver.PostgresDriver.simple._
import play.api.Play.current
case class DepartmentManager(id:Int,name:String,manager:String="")
case class Department(id:Option[Int],name:String,managerId:Option[Int])
class Departments (tag: Tag) extends Table[Department](tag, "DEPARTMENTS") {
  val employees = TableQuery[Employees]
  def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
  def name = column[String]("NAME", O.NotNull)
  def managerId = column[Int]("MANAGER_ID", O.Nullable)
  def manager = foreignKey("EMP_FK",managerId,employees)(_.id)
  def * = (id.?,name,managerId.?) <> (Department.tupled, Department.unapply)
}

object Departments{
  val db = play.api.db.slick.DB
  val departments = TableQuery[Departments]
//this is the problematic query
  def allWithMngr = db.withSession { implicit session =>
    val employees = TableQuery[Employees]
    val dm = (departments leftJoin employees ).list
    dm.map(x =>DepartmentManager(x._1.id.getOrElse(0),x._1.name, x._2.name + " " + x._2.last))
  }
}

デカルト積を取得しています (dm.size = 6 )

このようにクエリしようとしています:

val dm = (departments leftJoin employees on((a,b)=> a.id === b.id)).list

エラーが発生します:

[SlickException: ResultSet 列パス s2._4 の NULL 値 (null) を読み取る]

これは私の従業員モデルです:

case class Employee(name: String,last: String,email:Option[String]=None,phone:Option[String]=None,skype:Option[String]=None,department: Option[Int] = None, id: Option[Int] = None)
class Employees (tag: Tag) extends Table[Employee](tag, "EMPLOYEES") {
  def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
  def name = column[String]("NAME", O.NotNull)
  def last = column[String]("LAST", O.NotNull)
  def email = column[String]("EMAIL", O.Nullable)
  def phone = column[String]("PHONE", O.Nullable)
  def skype = column[String]("SKYPE", O.Nullable)
  def deptId = column[Int]("DEPT_ID", O.Nullable)
  def dept = foreignKey("EMP_FK",deptId,departments)(_.id)
  def * = (name,last,email.?,phone.?,skype.?,deptId.?, id.?) <> (Employee.tupled, Employee.unapply)
val departments = TableQuery[Departments]

}

出力として、このネイティブ Sql に相当するものが必要です:

val query =sql""" select x."ID", x."NAME", y."NAME" from "DEPARTMENTS" x  LEFT OUTER JOIN "EMPLOYEES" y ON (x."MANAGER_ID" = y."ID");""".as[DepartmentManager].list

結果は次のとおりです。

List (DepartmentManager(1,"FOO","AAA"),DepartmentManager(3,"XXX","BBB"),DepartmentManager(4,"FOO",""))
4

1 に答える 1

1

ここで遭遇しているのは、Slick 2 が結合で null を処理する厄介な方法です。Slick 3 の方が優れていますが、結合を Slick 2 で機能させることができます。

あなたが持っているクエリ...

(departments leftJoin employees ).list

... がないため、クロス結合になりますjoin

を使用するときに発生するエラーjoinは、選択する列の 1 つが NULL であるためです。Slick 2 では、これらの列を明示的に選択し.?て、オプションに昇格させる必要があります。

val query = 
   departments.leftJoin(employees).on(_.managerId === _.id )
              .map { case (d, e) => (d.id, d.name, e.name.?) }

部門に (従業員)e.name.?が存在しない可能性があるため、 --- に注意してください。e

テスト データを使用したこのクエリの結果は次のとおりです。

(1, FOO,   Some(AAA))
(2, XXX,   Some(BBB))
(3, dept1, None)

...それがあなたの求めているものだと思います。

于 2016-01-15T19:02:10.920 に答える