sql – Slick 2 – 更新表中的列并返回整个表对象

前端之家收集整理的这篇文章主要介绍了sql – Slick 2 – 更新表中的列并返回整个表对象前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在使用光滑时,如何在返回整个更新的表时更新表格表中的几列?

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

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

请注意,我知道您可以事先查询该项目,更新它,然后在原始对象上使用copy,但这需要大量的样板(以及数据库行程)

解决方法

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")))
原文链接:https://www.f2er.com/mssql/77094.html

猜你在找的MsSQL相关文章