此功能在Slick(v2或v3-M1)中不受支持;尽管我没有看到任何阻止其实施的具体原因,但UPDATE ... RETURNING
不是标准的SQL功能(例如,H2不支持它:http://www.h2database.com/html/grammar.html#update)。我将作为练习留给读者,探讨如何安全有效地模拟缺少UDPATE ... RETURNING
的RDBMS的功能。
当您致电scala.slick.lifted.Query
上的“返回”时,它会给您一个JdbcInsertInvokerComponent$ReturningInsertInvokerDef。你会发现没有update
方法,虽然有一个insertOrUpdate
方法;但是,insertOrUpdate
只返回returning
表达式结果,如果发生插入,则返回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, U, 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(_), _)) =>
children map { case Select(_, 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(_, compiled, CompiledMapping(_converter, _)) = 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")))
我不明白你是否要更新一个对象,并返回,或要更新的对象,然后有'TableQuery'你只是做了更新,如果第二,你可能只需要在正在执行的查询中追加'.run'。 –
假设我有一个从case类到表格列的完整投影,我想更新这些列的一个子集(即'.map(x =>(x.someColumn,x.anotherColumn)) '返回整个更新的对象(返回'SomeTables')。所以在上面的例子中,SomeTables可以有一个默认的'*'投影,它将有5个列,我正在更新其中的两列('someColumn'和'anotherColumn' ),但是我想返回包含5列的整个'table'(或object) – mdedetrich
从我的初学者经验来看,除了更新之外,我没有看到出路,然后选择行,'update'方法,重新调用返回一个'Int'(即更新是否成功)。抱歉,我无法帮助,希望有更多经验的人会回答。 –