在使用光滑时,如何在返回整个更新的表时更新表格表中的几列?
假设SoMetables是一些TableQuery,你通常会编写一个像这样的查询,例如,你想要一个项目添加到表中(并返回新添加的项目)
val returnedItem = SoMetables returning SoMetables += soMetable
如果你想要更新一个项目并将整个项目返回整个项目,你会怎么做?我怀疑你会做这样的事情
val q = SoMetables.filter(_.id === id).map(x => (x.someColumn,x.anotherColumn)) returning SoMetables val returnedItem = q.update((3,"test"))
但是以下代码不起作用,我看不到任何关于如何执行此操作的文档
解决方法
Slick(v2或v3-M1)不支持此功能;虽然我没有看到任何禁止它实现的具体原因,但UPDATE … RETURNING不是标准的sql功能(例如,H2不支持它:
http://www.h2database.com/html/grammar.html#update).我将作为练习留给读者探讨如何安全有效地模拟缺少UDPATE的RDBMS的功能…返回.
当你在scala.slick.lifted.Query上调用“return”时,它会给你一个JdbcInsertInvokerComponent$ReturningInsertInvokerDef.虽然有一个insertOrUpdate方法,但你找不到更新方法.但是,如果发生插入,insertOrUpdate仅返回返回的表达式结果,更新返回None,因此这里没有帮助.
由此我们可以得出结论,如果您想使用UPDATE … RETURNING sql功能,您需要使用StaticQuery或将自己的补丁滚动到Slick.您可以手动编写查询(并将表格投影重新实现为GetResult / SetParameter序列化程序),或者您可以尝试以下代码片段:
package com.spingo.slick import scala.slick.driver.JdbcDriver.simple.{queryToUpdateInvoker,Query} import scala.slick.driver.JdbcDriver.{updateCompiler,queryCompiler,quoteIdentifier} import scala.slick.jdbc.{ResultConverter,CompiledMapping,JdbcBackend,JdbcResultConverterDomain,GetResult,SetParameter,StaticQuery => Q} import scala.slick.util.sqlBuilder import slick.ast._ object UpdateReturning { implicit class UpdateReturningInvoker[E,U,C[_]](updateQuery: Query[E,C]) { def updateReturning[A,F](returningQuery: Query[A,F,C],v: U)(implicit session: JdbcBackend#Session): List[F] = { val ResultSetMapping(_,CompiledStatement(_,sres: sqlBuilder.Result,_),CompiledMapping(_updateConverter,_)) = updateCompiler.run(updateQuery.toNode).tree val returningNode = returningQuery.toNode val fieldNames = returningNode match { case Bind(_,_,Pure(Select(_,col),_)) => List(col.name) case Bind(_,Pure(ProductNode(children),_)) => children map { case Select(_,col) => col.name } toList case Bind(_,TableExpansion(_,TypeMapping(ProductNode(children),_)),Pure(Ref(_),col) => col.name } toList } implicit val pconv: SetParameter[U] = { val ResultSetMapping(_,compiled,CompiledMapping(_converter,_)) = updateCompiler.run(updateQuery.toNode).tree val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain,U]] SetParameter[U] { (value,params) => converter.set(value,params.ps) } } implicit val rconv: GetResult[F] = { val ResultSetMapping(_,_)) = queryCompiler.run(returningNode).tree val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain,F]] GetResult[F] { p => converter.read(p.rs) } } val fieldsExp = fieldNames map (quoteIdentifier) mkString "," val sql = sres.sql + s" RETURNING ${fieldsExp}" val unboundQuery = Q.query[U,F](sql) unboundQuery(v).list } } }
我确信上面的内容可以改进;我是基于对Slick内部的一些有限的理解而编写的,它对我有用,可以利用你已经定义的投影/类型映射.
用法:
import com.spingo.slick.UpdateReturning._ val tq = TableQuery[MyTable] val st = tq filter(_.id === 1048003) map { e => (e.id,e.costDescription) } st.updateReturning(tq map (identity),(1048003,Some("such cost")))