具有一对多关系的光滑查询

Slick query with one to many relationship

我正在使用 slick 3.2.3,我正在尝试构建一个 returns 一个 Seq[Entity1, Seq[Entity2]] 的查询,用于两个具有一对多关系的实体(每个 Entity1 都关联多个 Entity2).

所以我有两个实体

case class Entity1(name: String, id: Option[Long] = None)
case class Entity2(entity1Id: Long, name: String, id: Option[Long] = None

使用 table 定义(由 slick codegen 任务生成)

class entity1Table(_tableTag: Tag) extends profile.api.Table[Entity1](_tableTag, "ENTITY_1") {
   ...
}
lazy val groupTable = new TableQuery(tag => new groupTable(tag))

class entity2Table(_tableTag: Tag) extends profile.api.Table[Entity2](_tableTag, "ENTITY_2") {
   ...
}
lazy val entity2Table = new TableQuery(tag => new entity2Table(tag))

正在阅读 this article 我创建了一个这样的查询

val q = (for {
  e1 <- entity1Table
  e2 <- entity2Table if e2.entity1Id === e1.id
} yield (e1, e2)).groupBy(_._1) map {
  case (entity1, tuples) => (entity1, tuples.map(_._2))
}

db.run(q.result)

但是我在编译时得到这个错误:

Error:(19, 35) No matching Shape found.
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection,
 you use an unsupported type in a Query (e.g. scala List),
 or you forgot to import a driver api into scope.
  Required level: slick.lifted.FlatShapeLevel
     Source type: (my.namespace.models.entity1Table, slick.lifted.Query[my.namespace.models.entity2Table,my.namespace.models.Entity2,[+A]Seq[A]])
   Unpacked type: T
     Packed type: G
    } yield (e1, e2)).groupBy(_._1) map {

我怀疑它不能映射entity1Table和entity2Table。

如何修复错误?

Slick doc 中所述,groupBy 目前不支持使用 Query:

类型的嵌套值执行查询

The intermediate query (i.e. the query ended with groupBy() without an aggregate function) contains nested values of type Query. These would turn into nested collections when executing the query, which is not supported at the moment. Therefore it is necessary to flatten the nested queries immediately by aggregating their values (or individual columns)

换句话说,您的 Slick groupBy 查询必须与等价于 SQL 的 count()sum() 等的聚合函数耦合。例如,以下等效于 select count(*) ... group by ... having count(*) > 1 的查询将起作用:

val query = ( for {
    e1 <- entity1Table
    e2 <- entity2Table if e2.entity1Id === e1.id
  } yield (e1, e2)
).
groupBy(_._1).map{
  case (entity1, group) => (entity1, group.size)
}.
filter(_._2 > 1)