3

是否可以在预编译的 Slick 查询中使用集合作为参数?

就像是:

private val findByIds = for {
  ids <- Parameters[Set[Int]]
  meta <- AssetMetadatas if meta.id inSet ids
} yield meta

不幸的是,上面没有编译:

不知道如何将 scala.collection.immutable.Set[Int] 解包到 scala.collection.immutable.Set[Int] 并打包到 Any ids <- Parameters[Set[Int]] ^

4

2 回答 2

9

目前,您无法使用 inSet 预编译查询,无论是在 Slick 1 中还是在 Slick 2 中。当您考虑到 SQL 中的查询必须针对不同的 Set 大小而有所不同时,这是有道理的。

  • 对于 0:WHERE false
  • 1:WHERE id = ?
  • 2:WHERE id IN (?,?)
  • 3:WHERE id IN (?,?,?)
  • ...

这一般不能预编译,所以 Slick 每次都要为它编译 SQL。我们可能会在某些时候为某些后端提供支持。如果这很重要,您可以自己为选定的集合大小预编译几个查询(使用&&and==而不是inSet)。

使用inSetBind而不是inSet将集合作为参数传递给准备好的语句,而不是将它们作为文字编译到 SQL 字符串中。如果您以这种方式配置,这允许您的连接池缓存准备好的语句。所以 Slick 仍然需要编译查询,但至少你的数据库可以缓存查询计划。

于 2013-11-12T13:02:04.297 回答
2

为此inSetBind

private def findByIds(ids: Set[Int]) = for {
  meta <- AssetMetadatas if meta.id inSetBind ids
} yield meta

是的,这将在您每次调用 时调用查询编译器findByIds,但对于相同的基数,它总是会产生相同的 SQL ids

因此对于ids生成Set(1,2,3)的 SQL 将生成,

SELECT * from AssetMetadatas WHERE ID IN (?, ?, ?)

并且将在(1, 2, 3)调用查询时绑定。当您调用时,查询编译器将再次运行,findByIds(Set(4,5,6))但将生成完全相同的 SQL。即使假设 slick 不缓存编译后的 AST 结果,与数据库级别的节省(使用绑定参数)相比,这仍然是一个很小的成本。

于 2013-11-12T12:23:32.623 回答