更新表中的列并返回整个表对象

如何在使用浮油的同时返回整个更新表时更新表格中的几列?

假设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"))

但是下面的代码不起作用,我看不到有关如何执行此操作的任何文档

请注意,我知道您可以事先查询该项目,更新它,然后在原始对象上使用副本,但是这需要大量的样板(以及DB跳闸)


Slick(v2或v3-M1)不支持此功能; 尽管我没有看到任何禁止它实现的具体原因,但UPDATE ... RETURNING不是一个标准的SQL功能(例如,H2不支持它:http://www.h2database.com/html/grammar.html#更新)。 我将作为练习留给读者,探讨如何安全有效地模拟缺乏UDPATE ... RETURNING RETURNING的RDBMS的功能。

当您在scala.slick.lifted.Query调用“返回”时,它将为您提供一个JdbcInsertInvokerComponent $ ReturningInsertInvokerDef。 尽管有一个insertOrUpdate方法,你会发现没有update方法。 然而, 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")))
链接地址: http://www.djcxy.com/p/78863.html

上一篇: Update columns in a table and return whole table object

下一篇: Convert structure from C to Delphi