Cette fonction n'est pas supporté dans Slick (v2 ou v3-M1); Bien que je ne vois aucune raison spécifique interdisant son implémentation, UPDATE ... RETURNING
n'est pas une fonctionnalité SQL standard (par exemple, H2 ne la prend pas en charge: http://www.h2database.com/html/grammar.html#update). Je vais laisser comme un exercice au lecteur d'explorer comment on peut émuler efficacement et en toute sécurité la fonction pour les SGBDR qui n'ont pas UDPATE ... RETURNING
.
Lorsque vous appelez "return" sur un scala.slick.lifted.Query
, il vous donne un JdbcInsertInvokerComponent$ReturningInsertInvokerDef. Vous ne trouverez aucune méthode update
, bien qu'il existe une méthode insertOrUpdate
; Toutefois, insertOrUpdate
renvoie uniquement le résultat de l'expression returning
si une insertion se produit, None
est retourné pour les mises à jour, donc pas d'aide ici. De cela, nous pouvons conclure que si vous souhaitez utiliser la fonctionnalité SQL UPDATE ... RETURNING
, vous devrez utiliser StaticQuery ou lancer votre propre patch vers Slick. Vous pouvez écrire manuellement vos requêtes (et re-mettre en œuvre vos projections de table comme GetResult/SetParameter serializers), ou vous pouvez essayer ce bout de code:
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
}
}
}
Je suis certain que le ci-dessus peut être améliorée; Je l'ai écrit sur la base de ma compréhension quelque peu limitée des internes Slick, et cela fonctionne pour moi et peut tirer parti des projections/mappages de types que vous avez déjà définis.
Utilisation:
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")))
Je ne comprends pas si vous souhaitez mettre à jour un objet et de le retourner ou que vous souhaitez mettre à jour un objet et ensuite la 'TableQuery' avec la mise à jour que vous venez de faire, si le Deuxièmement, il suffit probablement d'ajouter '.run' à la requête que vous exécutez. –
En supposant que j'ai une projection complète d'une 'classe de cas' aux colonnes de la table, je veux mettre à jour un sous-ensemble de ces colonnes (ie le' .map (x => (x.someColumn, x.anotherColumn)) 'et retourne l'objet complet (en retournant' SomeTables') Donc dans l'exemple ci-dessus, SomeTables pourrait avoir une projection '*' par défaut qui aurait 5 colonnes, je suis en train de mettre à jour deux de ces colonnes ('someColumn' et' anotherColumn'), mais je veux retourner l'ensemble de la table (ou objet) qui contiendrait 5 colonnes – mdedetrich
De mon expérience de débutant, je ne vois pas d'issue, sauf pour la mise à jour, puis sélectionnez la ligne, la méthode 'update' vous ' re invoquant renvoie un 'Int' (que la mise à jour soit réussie ou non) Désolé, je n'ai pas pu aider, j'espère que quelqu'un avec plus d'expérience répondra –