2014-05-09 11 views
7

Come aggiorneresti alcune colonne in una tabella mentre restituisci l'intera tabella aggiornata quando utilizzi slick?Slick 2: aggiorna le colonne in una tabella e restituisce l'intero oggetto tabella

Supponendo SomeTables è una certa TableQuery, è in genere scrivere una query come questo se si vuole, ad esempio, aggiungere un elemento al tavolo (e restituzione del prodotto appena aggiunto)

val returnedItem = SomeTables returning SomeTables += someTable 

come ti fare lo stesso se si desidera aggiornare una voce e restituire tutta la schiena tutta la voce, ho il sospetto che si dovrebbe fare qualcosa di simile

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

il seguente codice però non funziona, e non riesco a vedere alcuna documentazione su come fare th è

Nota di essere a conoscenza si può solo interrogare l'oggetto in anticipo, il suo aggiornamento, e quindi utilizzare la copia per l'oggetto originale, ma questo richiede un sacco di boilerplate (e DB viaggi pure)

+0

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

+0

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

+0

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

risposta

4

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

Grazie! Sarebbe bello se ci fosse una versione aggiornata di Slick 3.0 :-) –

+0

C'è qualche differenza riguardo a questo in Slick 3? – Ixx

+0

Non abbiamo ancora eseguito l'aggiornamento a Slick 3; Sono certo che l'approccio generale funzionerà, ma è probabile che le API e le strutture dati presentino delle modifiche. –

Problemi correlati