18

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 虚拟化?它使用其他方法吗?

4

2 回答 2

32

Slick 的稳定 API通过它所谓的提升嵌入来实现这一点。您的示例显然使用了稳定的 API(正如您===用于相等而不是==)。

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

使用以下方式实现向 SQL 的转换:

  1. Scala 的for理解语法,被翻译为方法调用。Slick 中定义的表是Monads - 它们具有神奇foreach的 , map, flatMapfilter方法,允许它们在for“循环”中表达,而 Scala 将它们转换为方法调用(如@emil-ivanov 的另一个答案提供的代码中正确说明的那样)。

    与常规的 Scala 集合一样, is 用于对/和;for的嵌套方法调用的语法糖。常规集合不同,Slick对象的版本和查询的返回表示 ,与每个过滤条件 ( ) 或连接 (如)一起构建flatMapmapfilterTablemapfilterifs <- Suppliers if s.id is c.supID

    因此,类型不是q2您通常的集合(因为 Scala 中的 for 理解通常用于返回),而是查询的表示。(就像Scala Option Monad也适用于for理解,尽管它不是一个“集合”(以那样的方式ListMap

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

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

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

于 2012-12-07T07:27:16.563 回答
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(and foreach) 实际上并不过滤集合,而是收集 AST(抽象语法树)中的内容,然后将其处理给 Slick 以转换为 SQL。

此外,c.price,c.supID实际上是 Slick column,其<, >, ===(等等)方法不返回 bool,但也会收集比较,然后将其传递下来以转换为 SQL。

这是创作者的一次演讲,其中大部分内容都被描述(正确)。

于 2012-12-07T07:21:49.357 回答