Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 光滑模式leftJoin生成笛卡尔积_Scala_Playframework_Slick_Scalaquery - Fatal编程技术网

Scala 光滑模式leftJoin生成笛卡尔积

Scala 光滑模式leftJoin生成笛卡尔积,scala,playframework,slick,scalaquery,Scala,Playframework,Slick,Scalaquery,我有两张桌子: select * from "DEPARTMENTS"; ID | NAME | MANAGER_ID ----+-------+------------ 1 | FOO | 1 3 | XXX | 2 4 | dept1 | (3 rows) select * from "EMPLOYEES"; NAME | LAST | EMAIL | PHONE | SKY

我有两张桌子:

    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))
  }
}
结果出现错误:

[SlickException:读取结果集列路径的NULL值NULL s2._4]

这是我的员工模型:

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]

}
这将导致:

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

你在这里遇到的是Slick 2处理连接中空值的笨拙方式。在Slick 3中情况更好,但我们可以在Slick 2中加入工作

您的查询

(departments leftJoin employees ).list
…将是交叉连接,因为您没有连接

使用联接时遇到的错误是因为要选择的列之一为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)

…我想这正是您想要的。

您能以表格形式给出您想要的输出示例吗?离题:如果数据库设计尚未解决,我建议使用关系表而不是可为空的外键。这样可以避免一些边缘情况,并简化查询。@Jus12我现在做了,谢谢你的评论。除了SQL之外,表格式将更有帮助。我们需要的是实际的查询和返回的数据。@Jus12它实际上在查询列表departmentmanager下面……谢谢,这正是我要找的。现在清楚多了
val query = 
   departments.leftJoin(employees).on(_.managerId === _.id )
              .map { case (d, e) => (d.id, d.name, e.name.?) }
(1, FOO,   Some(AAA))
(2, XXX,   Some(BBB))
(3, dept1, None)