Scala+Slick 3:将一个查询的结果插入另一个 table

Scala+Slick 3: Inserting the result of one query into another table

这个问题是关于 slick 3.0 或 3.1 的(我对此很灵活)

我有一个中间查询,我用 mapfor 等处理以获得我想要的结果。最后我有一个

val foo: DBIOAction[Seq[MySchema.Bar], NoStream, Effect.Read]

现在我有一个 val bar: TableQuery[MySchema.Bar],我想在其中插入 foo。

如果 foo 是 Seq 我可以简单地做 bar ++= foo,但它不是。

我找到的唯一方法是通过等待来实现结果。像这样

val query = (bar ++= Await.result(db.run(foo), Duration.Inf))

显然 query 在某些时候需要 运行 db.run。但是现在我有两个 DB-运行s。将所有内容放在一个 运行 中不是更好吗?

有更好的方法吗?

DBIOActionmap/flatMap 函数,所以你可以这样写

val insertAction = foo.flatMap(bar ++= _)

insertAction 将是 DBIOAction[Int, NoStream, Effect.Write] 或类似的类型(我不完全确定 Int 和效果),然后你可以 运行它在数据库上作为任何 DBIOAction 使用 db.run;然后你得到的是整个查询和插入结果的未来。

问题已经得到解答,但我来这里是为了寻找不同的解决方案,所以这可能对其他人有所帮助。

正如@Aldo 所说,我们希望尽可能在 DBIO 级别工作,但我会更进一步说你应该尽可能在 Query 级别工作,因为它编译为可以发送到数据库的单个 sql 语句。

例如,来自 select 的插入应编译为 INSERT INTO table1 SELECT...。如果您使用 flatMap 的多个 DBIOS,就像建议的那样,这将被编译成一个 SELECT,这些值将被带到内存中,然后一个 INSERT 语句将被编译,插入这些值在一个字符串中,这个新查询将被发送到数据库。实际上,如果您的 select returns 许多结果,这可能会慢得多,并且在最坏的情况下它会耗尽您的内存。

因此,要将类似这样的内容编译成单个查询,您可以编写:

val bar: TableQuery[MySchema.Bar]

val foo: Query[MySchema.Bar, Bar, Seq]

val insert: DBIO[Int] = bar.forceInsertAll(foo)