如何建模与Slick的反向关系?

时间:2017-02-13 18:58:52

标签: scala slick

我试图在Slick 3.1.0-M1

中模拟多对多关系

这是Slick文档的示例

// Definition of the SUPPLIERS table
class Suppliers(tag: Tag) extends Table[(Int, String, String, String, String, String)](tag, "SUPPLIERS") {
  def id = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column
  def name = column[String]("SUP_NAME")
  def street = column[String]("STREET")
  def city = column[String]("CITY")
  def state = column[String]("STATE")
  def zip = column[String]("ZIP")
  // Every table needs a * projection with the same type as the table's type parameter
  def * = (id, name, street, city, state, zip)
}
val suppliers = TableQuery[Suppliers]

// Definition of the COFFEES table
class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
  def name = column[String]("COF_NAME", O.PrimaryKey)
  def supID = column[Int]("SUP_ID")
  def price = column[Double]("PRICE")
  def sales = column[Int]("SALES")
  def total = column[Int]("TOTAL")
  def * = (name, supID, price, sales, total)
  // A reified foreign key relation that can be navigated to create a join
  def supplier = foreignKey("SUP_FK", supID, suppliers)(_.id)
}
val coffees = TableQuery[Coffees]

我希望能够将供应商的案例类编写为

case class Supplier(
  id: Int,
  name: String,
  street: String,
  city: String,
  state: String,
  zip: String,
  coffees: List[Coffee]
)

我正在尝试这样做,但此刻我无法使其发挥作用。另外,我希望有一些方法允许以级联模式更新Supplier对象和Coffee对象。

1 个答案:

答案 0 :(得分:6)

答案很简单:你不能SlickFRM(函数关系映射)并简单地说 - 它将关系元组映射到Scala对象(通常是tuples / case classes)。您想要实现的内容在标准SQL中不易表达,因此无法直接在Slick中表达。我在这里特别提到标准SQL - 因为我知道有些数据库允许您将某些字段分组并聚合到列表或数组中 - 但这远远超出了标准SQL范围,老实说我甚至都不是确保你能够在一般情况下这样做。

您可以在某种程度上模仿查询,在SELECT之间使用JOIN在两个表之间进行分组,然后对结果进行分组(这里重要的是 - 结果,我不是在谈论SQL { {1}} )获取GROUP BY列表。

这可能是这样的:

首先 - 将您的表定义映射到案例类 - 所以代替:

coffees

这样做:

class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)]

并且可能将现有的class Coffees(tag: Tag) extends Table[Coffee] 案例类重命名为Supplier或其他任何意味着它没有严格映射到db表但又是两个不同表的组合。

SupplierComposite相同。 它并不是严格要求的(你的元组会很好) - 它只会让事情变得更容易。

然后你会像这样运行你的查询:

Supplier

无法无论如何实现这样的目标:

  

此外,我想有一些方法允许以级联模式更新Supplier对象和Coffee对象。

这些功能根本不属于db.run( ( suppliers join coffees on (_.id === _.supID) ) .result .map { results: Seq[(Supplier, Coffee)] => results .groupBy(_._1) .map { case (supp, groupped) => SupplierComposite( id = supp.id, name = supp.name, ... coffees = groupped.map(_._2) ) } } ) 试图实现的功能。绝对是经典的Slick s的触手可及 - 如Hibernate或(来自Scala世界)eBean

然而,请注意 - 这个特征(如上所述)基本上是ORM中固有的问题根源的起点之一 - 即object relational impedance mismatch - 正是这个问题ORM希望避免。