4

参考这个问题。
我想通过某种条件插入一些实体。它可以插入也可以不插入。如果条件为真,则插入实体。我想在各种表中插入一些其他数据。它看起来像这样:

val q = sql"insert into some_table (some_field) select 42 where ...(some condition)"

val inserts = List(
  sql"insert ...",
  sql"insert ...",
  sql"insert ..."
)

for {
  id <- q.update.withGeneratedKeys[Long]("id")   
  _ <- inserts.reduce(_ ++ _).update.run
} yield id

问题是这不能编译,因为第一个插入是 afs2.Stream而第二个不是。

我试图_ <- inserts.reduce..._ = inserts.reduce. 该应用程序可以编译,但inserts在第二行不会发生。


UPD
我解决这个问题的可能方法:

...
for {
  idOpt <- q.update.withGeneratedKeys[Long]("id").compile.last   
  _ <- idOpt.fold(0.pure[ConnectionIO])(_ => inserts.reduce(_ ++ _).update.run)
} yield idOpt

这行得通,但恕我直言,这并不漂亮。有更好的方法吗?

4

1 回答 1

1

执行批量插入的一种方法 - 如果您有类似的数据 - 是使用updateMany-请参阅 doc

import doobie._
type PersonInfo = (String, Option[Short])

def insertMany(ps: List[PersonInfo]): ConnectionIO[Int] = {
  val sql = "insert into person (name, age) values (?, ?)"
  Update[PersonInfo](sql).updateMany(ps)
}

// Some rows to insert
val data = List[PersonInfo](
  ("Frank", Some(12)),
  ("Daddy", None))

此外,如果您删除.compile.last,您可以使用这样一个事实,即如果您的结果Stream q.update.withGeneratedKeys[Long]("id")empty,您将“提前退出” for-comprehension

所以总而言之,这是你可以做的:

import fs2.Stream

val result =
  // Now the for-comprehension operates on a Stream instead of an Option
  for {
    r <- q.update.withGeneratedKeys[Long]("id")   
    _ <- Stream.eval(insertMany(data)) // insertMany(data) is defined like in the snippet above
  } yield r

result.compile.last
于 2019-06-15T00:54:28.220 回答