Scala Slick 如何将 Scala 代码翻译成 JDBC?

Posted

技术标签:

【中文标题】Scala Slick 如何将 Scala 代码翻译成 JDBC?【英文标题】:How does Scala Slick translate Scala code into JDBC? 【发布时间】:2012-11-25 08:34:37 【问题描述】:

Slick如何翻译代码如:

val q2 = for 
  c <- Coffees if c.price < 9.0
  s <- Suppliers if s.id === c.supID
 yield (c.name, s.name)
for(t <- q2) println("  " + t._1 + " supplied by " + t._2)

进入 JDBC?

它是否使用 Scala 虚拟化?是否使用了其他方法?

【问题讨论】:

【参考方案1】:

Slick 的stable API 通过它所谓的lifted embedding 实现了这一点。您的示例显然使用了稳定的 API(因为您使用 === 表示相等而不是 ==)。

Slick(以及 Scala)的美妙之处在于 - 无需使用宏或 Scala-Virtualized 即可实现这一点。 (旁注:Slick 的实验 API 确实使用宏 - 这将允许您使用 == 而不是 ===is

到 SQL 的转换是通过以下方式实现的:

    Scala 的for 理解语法,被翻译为方法调用。 Slick 中定义的表是 Monads - 它们具有魔力 foreachmapflatMap,和 filter 允许它们在 Scala 中以 for 'loops' 表示的方法 将它们转换为方法调用(如代码中正确说明的那样 由the other answer by @emil-ivanov提供)。

    与常规的 Scala 集合一样,for 是嵌套的语法糖 对flatMap/mapfilter 的方法调用; 不同于常规收藏, 光滑的Table 对象版本的mapfilter 返回表示 查询,与每个过滤条件 (if) 一起构建它或加入 (如s &lt;- Suppliers if s.id is c.supID

    所以 q2type 不是你常用的集合(作为 Scala 中的理解 通常用于返回),而是查询的表示。 (正如Scala Option Monad 也适用于for 理解,尽管 不是“集合”(就像ListMap 那样))

    您可以使用q2.selectStatement 查看基础查询。

    Scala 的隐式 提升 - c.price 不是 Int 而是代表 列值 - 所以表达式 c.price &lt; 9.0 变为 c.price.&lt;(Const(9.0))Int 被提升为所需的类型),&lt; 只是 代表c.price 的类,一个Column&lt; 方法 不做&lt; 通常做的事情(在普通Ints 的情况下) - 它只是返回 对应于price &lt; 9 的 SQL AST 的表示形式,它成为 生成并发送到 JDBC 执行的 SQL。

在细节方面还有很多其他事情要做,但我认为查询单子和隐式提升是主要成分。

【讨论】:

非常棒的帖子。隐式提升很聪明【参考方案2】:

在 Scala 中,for“循环”实际上并不是一种特殊的语言结构,而是语法糖。你的第一个例子

val q2 = for 
  c <- Coffees if c.price < 9.0
  s <- Suppliers if s.id === c.supID
 yield (c.name, s.name)

翻译成以下几行:

val q2 = Coffees.withFilter(_.price < 9.0).flatMap(c =>
    Suppliers.withFilter(_.id === c.supID).map(s =>
        (c.name, s.name)
    )
)

现在,flatMapmapwithFilter(和foreach)实际上并不过滤集合,而是收集 AST(抽象语法树)中正在发生的事情,然后将其处理给 Slick翻译成 SQL。

另外,c.pricec.supID 实际上是 Slick columns,其 &lt;&gt;===(等等)方法不返回 bool,但也会收集比较, 哪一个 稍后传递下来以转换为 SQL。

This is a talk 由创作者提供,其中大部分内容已(正确)描述。

【讨论】:

以上是关于Scala Slick 如何将 Scala 代码翻译成 JDBC?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Scala Slick 中运行补丁/部分数据库更新?

Scala / Slick,“等待连接 20000 毫秒后超时”错误

Scala Slick 无法将查询与计数联合起来

如何使用 Play with Scala 和 Slick 从数据库中获取记录

将 Scala Slick 与数据库枚举一起使用

Scala + Play Framework + Slick - Json 作为模型字段