【发布时间】:2014-08-28 11:02:44
【问题描述】:
我有一个数据库,其中包含具有一对多注册关系的活动。 目标是获取所有活动及其注册列表。
通过创建带有注册的活动的笛卡尔积,获取该数据所需的所有数据都在那里。
但我似乎找不到一个很好的方法将它正确地放入 scala 集合中;
让我们输入:Seq[(Activity, Seq[Registration])]
case class Registration(
id: Option[Int],
user: Int,
activity: Int
)
case class Activity(
id: Option[Int],
what: String,
when: DateTime,
where: String,
description: String,
price: Double
)
假设存在适当的光滑表和表查询,我会写:
val acts_regs = (for {
a <- Activities
r <- Registrations if r.activityId === a.id
} yield (a, r))
.groupBy(_._1.id)
.map { case (actid, acts) => ??? }
}
但我似乎无法做出适当的映射。这样做的惯用方式是什么?我希望它比使用原始笛卡尔积更好...
在 Scala 中
在 scala 代码中很简单,看起来像这样:
val activities = db withSession { implicit sess =>
(for {
a <- Activities leftJoin Registrations on (_.id === _.activityId)
} yield a).list
}
activities
.groupBy(_._1.id)
.map { case (id, set) => (set(0)._1, set.map(_._2)) }
但这似乎相当低效,因为表映射器将为您创建不必要的 Activity 实例化。 看起来也不是很优雅……
获取注册计数
当只对这样的注册计数感兴趣时,in scala 方法更糟糕:
val result: Seq[Activity, Int] = ???
在光滑
我对 slick 的最佳尝试如下所示:
val activities = db withSession { implicit sess =>
(for {
a <- Activities leftJoin Registrations on (_.id === _.activityId)
} yield a)
.groupBy(_._1.id)
.map { case (id, results) => (results.map(_._1), results.length) }
}
但这会导致 slick 无法在“map”行中映射给定类型的错误。
【问题讨论】:
-
count版本至少有简单路径described in the docs
-
与文档的不同之处在于我对整个活动以及对其注册的聚合感兴趣。而且我不知道如何映射。你能帮忙吗?
-
明确一点:我想要类似的东西:
SELECT l.*, count(r.id) from activities l join registrations r where l.id = r.activityId;并将其映射到Seq[(Activity, Int)] -
刚刚阅读您的最后一条评论.. 不确定这是否可行,但您是否尝试过
groupBy(_._1),然后应该将整个活动实体作为键吐出。 -
另外.. 您最初的问题是询问活动和相关注册列表。我之前遇到过类似的问题,并通过对数据库进行两次调用来解决此要求,一次使用
.head进行投影,另一次使用.list进行投影。我知道这会对数据库进行两次“调用”,但是因为我们有一个打开的会话/连接,所以实际开销非常小。如果您不介意将问题表达为两个调用(即更多代码),那么我认为您可以通过这种方式实现目标。