2014-05-09 5 views
7

Comment mettriez-vous à jour quelques colonnes dans une table de table tout en retournant la table entière mise à jour en utilisant slick?Slick 2 - Mettre à jour les colonnes dans une table et retourner l'objet table entière

En supposant SomeTables est une TableQuery, vous généralement écrire une requête comme si vous le souhaitez, par exemple, ajouter un élément à la table (et en retournant le nouveau ajouté article)

val returnedItem = SomeTables returning SomeTables += someTable 

Comment qualifieriez-vous faire la même chose si vous souhaitez mettre à jour un élément et retourner tout le dos tout l'article, je pense que vous feriez quelque chose comme ça

val q = SomeTables.filter(_.id === id).map(x => (x.someColumn,x.anotherColumn)) returning SomeTables 
val returnedItem = q.update((3,"test")) 

le code suivant ne fonctionne cependant pas, et je ne vois pas la documentation sur la façon de faire est

Notez que je suis conscient que vous pouvez simplement interroger l'élément au préalable, mettre à jour, et ensuite utiliser une copie de l'objet original, mais cela nécessite beaucoup de passe-partout (et DB voyages ainsi)

+0

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. –

+0

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

+0

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 –

Répondre

4

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"))) 
+2

Merci! Ce serait génial s'il y avait une version mise à jour pour Slick 3.0 :-) –

+0

Y at-il une différence à ce sujet dans Slick 3? – Ixx

+0

Nous n'avons pas encore mis à jour vers Slick 3 ici; Je suis sûr que l'approche générale fonctionnera, mais il est probable que les API et les structures de données ont quelque peu changé. –

Questions connexes