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 - 它们具有魔力 foreach
、map
、
flatMap
,和
filter
允许它们在 Scala 中以 for
'loops' 表示的方法
将它们转换为方法调用(如代码中正确说明的那样
由the other answer by @emil-ivanov提供)。
与常规的 Scala 集合一样,for
是嵌套的语法糖
对flatMap
/map
和filter
的方法调用; 不同于常规收藏,
光滑的Table
对象版本的map
和filter
返回表示
查询,与每个过滤条件 (if
) 一起构建它或加入
(如s <- Suppliers if s.id is c.supID
)
所以 q2
的 type 不是你常用的集合(作为 Scala 中的理解
通常用于返回),而是查询的表示。
(正如Scala Option Monad 也适用于for
理解,尽管
不是“集合”(就像List
或Map
那样))
您可以使用q2.selectStatement
查看基础查询。
Scala 的隐式 提升 - c.price
不是 Int
而是代表
列值 - 所以表达式 c.price < 9.0
变为 c.price.<(Const(9.0))
(Int
被提升为所需的类型),<
只是
代表c.price
的类,一个Column
。 <
方法
不做<
通常做的事情(在普通Int
s 的情况下) - 它只是返回
对应于price < 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)
)
)
现在,flatMap
、map
、withFilter
(和foreach
)实际上并不过滤集合,而是收集 AST(抽象语法树)中正在发生的事情,然后将其处理给 Slick翻译成 SQL。
另外,c.price
、c.supID
实际上是 Slick column
s,其 <
、>
、===
(等等)方法不返回 bool,但也会收集比较, 哪一个
稍后传递下来以转换为 SQL。
This is a talk 由创作者提供,其中大部分内容已(正确)描述。
【讨论】:
以上是关于Scala Slick 如何将 Scala 代码翻译成 JDBC?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Scala Slick 中运行补丁/部分数据库更新?
Scala / Slick,“等待连接 20000 毫秒后超时”错误