Slick 3多个外连接

14

从Slick文档中可以明确了解如何在两个表之间进行单个左连接。

val q = for {
  (t, v) <- titles joinLeft volumes on (_.uid === _.titleUid)
} yield (t, v)

查询 q 会有以下属性:_1 类型为 Titles_2 类型为 Rep[Option[Volumes]],以对不存在的卷进行覆盖。

进一步的级联操作存在问题:

val q = for {
  ((t, v), c) <- titles 
                     joinLeft volumes on (_.uid === _.titleUid)
                     joinLeft chapters on (_._2.uid === _.volumeUid)
} yield /* etc. */

这样做行不通,因为_._2.uid === _.volumeUid是无效的,因为_.uid不存在。

根据网络上的各种来源,这不应该是个问题,但是毕竟不同的源针对不同的slick版本,3.0仍然相对较新。有人对此问题有什么线索吗? 澄清一下,想法是使用两个左连接从三个级联1:n:n表中提取数据。 等效的SQL语句如下:

Select *
from titles
left join volumes
    on titles.uid = volumes.title_uid
left join chapters
    on volumes.uid = chapters.volume_uid

1
可能是multiple joins with slick的重复问题。 - Sean Vieira
那个答案是针对Slick 2的。 - LowFieldTheory
1个回答

28
您的第二个左连接不再针对TableQuery[Titles],而是针对实际上是Query[(Titles, Option[Volumes])] (忽略结果和集合类型参数)。当您在TableQuery[Chapters]上加入结果查询时,可以使用_2字段访问元组中的第二个条目(因为它是一个Option,您需要map来访问uid字段):
val q = for {
  ((t, v), c) <- titles 
                     joinLeft volumes on (_.uid === _.titleUid)
                     joinLeft chapters on (_._2.map(_.uid) === _.volumeUid)
} yield /* etc. */

避免使用TupleN

如果_N字段的语法不清楚,你也可以使用Slick的用户定义记录类型功能来进行行映射:

// The `Table` variant of the joined row representation
case class TitlesAndVolumesRow(title: Titles, volumes: Volumes)

// The DTO variant of the joined row representation
case class TitleAndVolumeRow(title: Title, volumes: Volume)

implicit object TitleAndVolumeShape
  extends CaseClassShape(TitlesAndVolumesRow.tupled, TitleAndVolumeRow.tupled)

嗨Sean - 我在问题中更正了我的代码,并添加了_2.uid。实际上,这就是问题所在,因为在表达式中: joinLeft chapters on (_._2.uid === _.volumeUid) _.2不是Volumes类型,而是Rep [Option [Volumes]]类型。因此,._2.uid不可用,这就是问题的根源。 - Bruno Batarelo
@布鲁诺 - 更新为我相信是3.0的正确语法 - Sean Vieira
我将答案标记为正确,因为它可以编译。但是,不幸的是,由于我目前在slick中遇到其他问题,我无法完全测试它。谢谢! - Bruno Batarelo
如果你把所有的 joinLeft 写在一行,它就能编译通过。至少对我是这样。 - omnomnom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接