如何定义空查询

How to define an empty query

for-comp 中,我需要设置一些查询,然后 运行 稍后在单次拍摄中......比如:

val queries = for {
  _ <-  query1
  _ <-  query2
  id <- someInsertQuery
} yield id

db.run(queries.transactionally)

提示:查询是slick.jdbc.JdbcActionComponent#ProfileAction

的实例

现在,我需要为前两个查询设置条件。如果满足条件,查询应该 运行,否则没有。所以我想:

val queries = for {
  _ <-  if (condition1) query1 else Query.empty
  _ <-  if (condition2) query2 else Query.empty
  id <- someInsertQuery
} yield id

db.run(queries.transactionally)

但这行不通:

value flatMap is not a member of Object
[error]  _ <- if (condition1) query1 else Query.empty
[error]       ^

所以我敢打赌我想做的不是这种方式。实现这一目标的正确方法是什么?

更新1: 更多细节。 for-comp 中的第一项如下所示(考虑 Boris 的想法):

val queries = for {
  _ <- someOption.map(someRow => SomeTableQuery += someRow).geOrElse(Query.empty.result)
}

SomeTableQueryslick.lifted.TableQuery[SomeClass] 的实例,someOptionOption[SomeClass]

到目前为止,我能够解决它的最好方法是在 filter 中获取条件。大致:

val queries = for {
  _ <-  query1.filter(condition1)
  _ <-  query2.filter(condition2)
  id <- someInsertQuery
} yield id

db.run(queries.transactionally)

如果您有其他想法,请告诉我。

我认为您对 for-yield 构造有一些误解。 在scala中,for-yield只是一些flatMapmap函数组合下的语法糖。

val queries = for {
  _ <-  if (condition1) query1 else Query.empty
  _ <-  if (condition2) query2 else Query.empty
  res <- someInsertQuery
} yield res

对于编译器,它等同于:

query1.flatMap(_ => query2.flatMap(_ => someInsertQuery.map(res => res)))

如果你的 query1query2ProfileAction:

val query1: ProfileAction[Int, NoStream, Effect.Write] = ???
val query2: ProfileAction[Int, NoStream, Effect.Write] = ???

所以,表达式 if (condition1) query1 else Query.empty 的类型是 Object,因为 Query.empty 的类型是 - Query[Unit, Unit, Seq]Query 的最近共同祖先并且ProfileActionObject 类型,没有 flatMap 功能。为了使您的代码可编译,您应该使 if ... else 构造的所有分支具有相同的类型并具有 flatMap 函数,如果我们在 Query.empty 上调用 result 就会这样:

val result1: FixedSqlAction[Any, NoStream, Effect.Write with Effect.Read] = if (condition1) query1 else Query.empty.result
val result2: FixedSqlAction[Any, NoStream, Effect.Write with Effect.Read] = if (condition2) query2 else Query.empty.result

您的代码的可能版本:

import slick.jdbc.JdbcBackend
import slick.lifted.Query
import slick.jdbc.H2Profile.api._

val db: JdbcBackend.Database = ???
val query1: ProfileAction[Int, NoStream, Effect.Write] = ???
val query2: ProfileAction[Int, NoStream, Effect.Write] = ???
val someInsertQuery: ProfileAction[Int, NoStream, Effect.Write] = ???

val condition1 = false
val condition2 = true

val queries = for {
  _ <-  if (condition1) query1 else Query.empty.result
  _ <-  if (condition2) query2 else Query.empty.result
  res <- someInsertQuery
} yield res
db.run(queries.transactionally)

如果您的查询实际上是选项而不仅仅是查询,您可以使用 flatMap 编写选项组合来过滤空选项,并使用 seq 来顺序执行结果查询序列。例如,在 slick documentation 中使用 table:

import slick.jdbc.H2Profile.api._

case class Coffees(tag: Tag) extends Table[(String, Double)](tag, "COFFEES") {
  def name = column[String]("COF_NAME")
  def price = column[Double]("PRICE")
  def * = (name, price)
}
val coffees: TableQuery[Coffees] = TableQuery[Coffees]

val maybeQuery1 = Option(("Colombian", 7.99))
val maybeQuery2 = Option(("Another name", 14.59))
val maybeQuery3 = Option(("Name", 4.39))
val queries = Seq(maybeQuery1, maybeQuery2, maybeQuery3).flatMap(_.map(someRow => coffees += someRow))

val db: Database = ???
db.run(DBIO.seq(queries:_*).transactionally)