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 虚拟化?它使用其他方法吗?
Slick 的稳定 API通过它所谓的提升嵌入来实现这一点。您的示例显然使用了稳定的 API(正如您===
用于相等而不是==
)。
Slick(以及 Scala)的美妙之处在于 - 无需使用宏或 Scala-Virtualized 即可实现这一点。 (旁注:Slick 的实验性 API确实使用宏 - 这将允许您使用==
而不是===
or is
)
使用以下方式实现向 SQL 的转换:
Scala 的for
理解语法,被翻译为方法调用。Slick 中定义的表是Monads - 它们具有神奇foreach
的 , map
,
flatMap
和
filter
方法,允许它们在for
“循环”中表达,而 Scala 将它们转换为方法调用(如@emil-ivanov 的另一个答案提供的代码中正确说明的那样)。
与常规的 Scala 集合一样, is 用于对/和;for
的嵌套方法调用的语法糖。与常规集合不同,Slick对象的版本和查询的返回表示
,与每个过滤条件 ( ) 或连接 (如)一起构建flatMap
map
filter
Table
map
filter
if
s <- Suppliers if s.id is c.supID
因此,类型不是q2
您通常的集合(因为 Scala 中的 for 理解通常用于返回),而是查询的表示。(就像Scala Option Monad也适用于for
理解,尽管它不是一个“集合”(以那样的方式List
)Map
)
您可以使用 来查看基础查询q2.selectStatement
。
Scala 的隐式提升-c.price
不是Int
一个列值的表示,而是一个列值的表示 - 所以表达式c.price < 9.0
变成c.price.<(Const(9.0))
(anInt
被提升到所需的类型),并且<
只是表示c.price
, a的类的一个方法Column
。该<
方法不做<
通常做的事情(在普通Int
s 的情况下) - 它只是返回 SQL AST 的表示形式,该表示形式对应于price < 9
生成并发送到 JDBC 执行的 SQL 的一部分。
就细节而言,还有很多其他事情要做,但我认为查询单子和隐式提升是主要成分。
在 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
(and foreach
) 实际上并不过滤集合,而是收集 AST(抽象语法树)中的内容,然后将其处理给 Slick 以转换为 SQL。
此外,c.price
,c.supID
实际上是 Slick column
,其<
, >
, ===
(等等)方法不返回 bool,但也会收集比较,然后将其传递下来以转换为 SQL。
这是创作者的一次演讲,其中大部分内容都被描述(正确)。