Questa funzione non è supportato in Slick (v2 o v3-M1); anche se non vedo alcun motivo specifico che ne impedisca l'implementazione, lo standard UPDATE ... RETURNING
non è una funzione SQL standard (ad esempio, H2 non lo supporta: http://www.h2database.com/html/grammar.html#update). Lascio un esercizio al lettore per esplorare come si possa emulare in modo sicuro ed efficiente la funzione per gli RDBMS privi di UDPATE ... RETURNING
.
Quando si chiama "ritorno" su un scala.slick.lifted.Query
, viene fornito un JdbcInsertInvokerComponent$ReturningInsertInvokerDef. Non troverai il metodo update
, sebbene esista un metodo insertOrUpdate
; tuttavia, insertOrUpdate
restituisce solo il risultato dell'espressione returning
se si verifica un inserto, None
viene restituito per gli aggiornamenti, quindi nessun aiuto qui.
Da ciò possiamo concludere che se si desidera utilizzare la funzione SQL UPDATE ... RETURNING
, è necessario utilizzare StaticQuery oppure eseguire il rollover della propria patch su Slick. È possibile scrivere manualmente le vostre domande (e ri-implementare le proiezioni da tavolo come GetResult/setParameter serializzatori), oppure si può provare questo frammento di codice:
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
}
}
}
Sono certo che quanto sopra può essere migliorata; L'ho scritto in base alla mia comprensione un po 'limitata degli interni di Slick, e funziona per me e può sfruttare le proiezioni/i tipi di mappatura che hai già definito.
Usage:
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")))
Non capisco se si desidera aggiornare un oggetto e restituirlo o si desidera aggiornare un oggetto e quindi avere la 'TableQuery' con l'aggiornamento che hai appena fatto, se il secondo probabilmente devi solo aggiungere ".run" alla query che stai eseguendo. –
Supponendo di avere una proiezione completa da una 'case class' alle colonne della tabella, voglio aggiornare un sottoinsieme di quelle colonne (es.' .map (x => (x.someColumn, x.anotherColumn)) 'e restituisce l'intero oggetto aggiornato (restituendo' SomeTables'). Quindi nell'esempio precedente, SomeTables potrebbe avere una proiezione '*' predefinita che avrebbe 5 colonne, Sto aggiornando due di queste colonne ('someColumn' e' anotherColumn'), tuttavia voglio restituire l'intero 'table' (o oggetto) che conterrebbe 5 colonne – mdedetrich
Dalla mia esperienza da principiante non vedo una via d'uscita tranne l'aggiornamento e quindi seleziono la riga, il metodo 'update' te' re invocando restituisce un 'Int' (cioè se l'aggiornamento ha avuto successo o meno). Scusa non ho potuto aiutare, si spera che qualcuno con più esperienza risponderà –