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

Scala+Slick 3:将一个查询的结果插入到另一个表中,scala,slick,slick-3.0,Scala,Slick,Slick 3.0,这个问题是关于slick 3.0或3.1的,我对此很灵活 我有一个中间查询,我用map、for等进行处理,以获得我想要的结果。最后我有一个 val foo: DBIOAction[Seq[MySchema.Bar], NoStream, Effect.Read] 现在我有了一个valbar:TableQuery[MySchema.bar],我想在其中插入foo 如果foo是一个Seq,我可以简单地做bar++=foo,但事实并非如此 我找到的唯一方法就是通过等待结果来实现结果。像这样 val

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

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

val foo: DBIOAction[Seq[MySchema.Bar], NoStream, Effect.Read]
现在我有了一个valbar:TableQuery[MySchema.bar],我想在其中插入foo

如果foo是一个Seq,我可以简单地做bar++=foo,但事实并非如此

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

val query = (bar ++= Await.result(db.run(foo), Duration.Inf))
显然,查询需要在某个时候使用db.run运行。但现在我有两个数据库运行。把所有东西都放在一次运行中不是更好吗

有更好的方法吗?

DBIOAction具有map/flatMap函数,因此您可以编写类似

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

插入操作将是DBIOAction[Int,NoStream,Effect.Write]或类似的类型,我不完全确定Int和效果,然后您可以使用DB.run在DB上像任何DBIOAction一样运行它;然后得到的是整个查询和插入结果的未来。

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

正如@Aldo所说,我们希望尽可能在DBIO级别上工作,但我想进一步说,您应该尽可能在查询级别上工作,因为这将编译成一条可以发送到数据库的sql语句

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

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

val bar: TableQuery[MySchema.Bar]

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

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

巴+=福?但是不管是+=还是+=,您仍然必须运行db。。。我认为有副作用的+++=是slick2 api,而slick3更具功能性,因此需要显式执行db.runYes++=的结果现在是需要运行的查询。我在这一点上编辑了这个问题。但是我必须为这个任务执行两个db.run调用。可能的flatMap副本会起作用。最后,我只剩下一个DBIOAction需要运行。关于这个主题,我遇到了另一件事:我应该什么时候运行db.run?下面是一个示例val foo=db.run persons.result.map_551;map{p=>trtdp.id}我可以这样做,也可以在.result之后结束db.run部分。这两种方法给了我相同的未来,在性能方面有什么不同吗?一般来说,您希望尽可能在DBIO级别工作;当您调用db.run时,slick将使用自己的执行上下文运行所需的查询,并在将来返回给您。我认为,如果您这样做的话,性能上会有潜在的差异,因为slick将优化线程在DB访问方面的使用。