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 Virtualized?它是否使用其他方法?
答案 0 :(得分:31)
Slick的稳定API 通过它所谓的提升嵌入来实现这一目标。您的示例显然正在使用稳定的API(因为您使用===
表示相等而不是==
)。
Slick(反过来Scala)的美妙之处在于 - 这可以在不使用宏或Scala-Virtualized的情况下实现。 (附注:Slick的实验性API 确实使用了宏 - 这样您就可以使用==
代替===
或is
)
使用以下方法实现对SQL的转换:
Scala的for
理解语法,转换为方法调用。
Slick中定义的表格是 Monads - 它们具有魔力foreach
,map
,
flatMap
,和
filter
方法允许它们在Scala中以for
'循环'表示
将它们转换为方法调用(如代码中正确说明的那样)
由the other answer by @emil-ivanov提供。
与常规Scala集合一样,for
是嵌套的语法糖
方法调用flatMap
/ map
和filter
; 与常规集合不同,
Table
和map
的Slick filter
个对象版本返回表示
查询,与每个过滤条件(if
)或连接一起构建它
(如s <- Suppliers if s.id is c.supID
)
所以q2
的类型不是你常用的集合(作为对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。
在细节方面还有很多其他事情,但我认为查询monad和隐含的提升是主要成分。
答案 1 :(得分:14)
在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
,其<
,>
,===
(等等)方法不要返回bool,但也要收集比较
稍后传递下来转换为SQL。
This is a talk,其中大部分内容都是(正确地)描述的。