How to model an inverse relationship with Slick?

↘锁芯ラ 提交于 2019-12-08 06:54:52

问题


I am trying to model a relationship many-to-many in Slick 3.1.0-M1

This is the example of the Slick documentation

// 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]

I would like to be able to write the case class of Suppliers as this

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

I am trying to do it, but at the moment I can not make it work. Also I would like to have methods that allow to update the Supplier object and the Coffee object inside in a cascade mode.


回答1:


The answer is simply: you cannot. Slick is FRM (functional relational mapping) and to put it simply - it maps relational tuples onto Scala objects (usually tuples / case classes). What you want to achieve is not expressed easily in standard SQL, therefore it is not expressible directly in Slick. I am specifically mentioning standard SQL here - as I am aware that some databases allow you to group and aggregate certain fields into lists or arrays - this is however far outside of standard SQL scope and honestly I am not even sure you would be able to do it in general case.

You can to some extent mimic above in queries by doing SELECT with JOIN between two tables and later grouping results (important thing here is - results, I am not talking about SQL GROUP BY) to obtain coffees list.

This could be something like this:

First - map your table definitions to cases classes - so instead of:

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

do this:

class Coffees(tag: Tag) extends Table[Coffee]

and perhaps rename your existing Supplier case class to SupplierComposite or whatever else that implies that it doesn't map strictly to db table but is rather a composition of two different tables.

Same with Supplier. It is not strictly required (you would be fine with your tuples) - it will only make things easier.

Then you would run your query like this:

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

It is not possible whatsoever to achieve things like this:

Also I would like to have methods that allow to update the Supplier object and the Coffee object inside in a cascade mode.

Such functions simply don't belong to what Slick tries to achieve. It is definitely though within reach of classic ORMs - like Hibernate or (from Scala world) eBean.

Be warned however - this feature (mentioned above) is basically one of the starting points of the root of the problem that is inherent in ORMs - namely object relational impedance mismatch - and is precisely the thing that Slick wanted to avoid.



来源:https://stackoverflow.com/questions/42211504/how-to-model-an-inverse-relationship-with-slick

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!