2015-06-28 8 views
22

Non riesco a comprendere la nuova API Slick DBIOAction, che non sembra avere molti esempi nei documenti. Sto usando Slick 3.0.0, e ho bisogno di eseguire alcune azioni DB e anche alcuni calcoli con i dati ricevuti dal database, ma tutte queste azioni devono essere fatte all'interno di una singola transazione. Sto cercando di eseguire quanto segue:Esecuzione di azioni non di database in una transazione in Slick 3

  1. Eseguire una query sul database (la tabella types).
  2. Effettua alcune aggregazioni e il filtraggio dei risultati della query (questo calcolo non può essere eseguito sul database).
  3. Esegui un'altra query, in base ai calcoli del passaggio 2 (la tabella messages - a causa di alcune limitazioni, questa query deve essere in SQL raw).
  4. Unire i dati dei passaggi 2 e 3 nella memoria.

Desidero che le query dei passaggi 1 e 3 siano eseguite all'interno di una transazione, in quanto i dati delle serie di risultati devono essere coerenti.

Ho provato a farlo in uno stile di join monadico. Ecco una versione eccessivamente semplificata del mio codice, ma non riesco nemmeno a farlo per compilare:

val compositeAction = (for { 
    rawTypes <- TableQuery[DBType].result 
    (projectId, types) <- rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))) 
    counts <- DBIO.sequence(types.map(aType => sql"""select count(*) from messages where type_id = ${aType.id}""".as[Int])) 
    } yield (projectId, types.zip(counts))).transactionally 
  1. La prima fila di for comprensione seleziona i dati dalla tabella types.
  2. Si suppone che la seconda fila di for comprensione fare qualche raggruppamento e tranciatura dei risultati, con un conseguente Seq[(Option[String], Seq[String])]
  3. La terza fila di for comprensione deve eseguire una serie di query per ogni elemento dal passaggio precedente, in In particolare, deve eseguire una singola query SQL per ciascuno dei valori all'interno di Seq[String]. Quindi nella terza riga costruisco una sequenza di DBIOAction s.
  4. yield clausola zip s types dal secondo passaggio e counts dal terzo passaggio.

Questa costruzione, tuttavia, non funziona e dà due errori in fase di compilazione:

Error:(129, 16) type mismatch; 
found : slick.dbio.DBIOAction[(Option[String], Seq[(com.centreit.proto.repiso.storage.db.models.DBType#TableElementType, Vector[Int])]),slick.dbio.NoStream,slick.dbio.Effect] 
    (which expands to) slick.dbio.DBIOAction[(Option[String], Seq[(com.centreit.proto.repiso.storage.db.models.TypeModel, Vector[Int])]),slick.dbio.NoStream,slick.dbio.Effect] 
required: scala.collection.GenTraversableOnce[?] 
     counts <- DBIO.sequence(types.map(aType => sql"""select count(*) from messages where type_id = ${aType.id}""".as[Int])) 
      ^
Error:(128, 28) type mismatch; 
found : Seq[Nothing] 
required: slick.dbio.DBIOAction[?,?,?] 
     (projectId, types) <- rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))) 
         ^

Ho cercato di avvolgere la seconda linea in un DBIOAction utilizzando DBIO.successful, che dovrebbe alzare un valore costante nel DBIOAction monad:

(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10)))) 

Ma in questo codice viene dedotta la variabile types sia Any, e il codice fa non compilare per questo.

+0

Date un'occhiata a [questo esempio] (https://github.com/slick/slick/issues/1093#issuecomment-110252046) e vedere se ti aiuta –

+0

@FelipeAlmeida Grazie, ma non è proprio quello di cui ho bisogno. In questo esempio, tutte le comprensioni sono aggiornamenti/eliminazioni/inserimenti, e non sono interconnessi dai loro risultati e non producono nulla (tutte le parti di sinistra sono '_').Nel mio caso, una delle mie azioni non ha nulla a che fare con il database e tutte le azioni restituiscono risultati che sono utilizzati in altre interpretazioni o nel 'rendimento'. –

risposta

15

Prova in questo modo:

val compositeAction = (for { 
    rawTypes <- TableQuery[DBType].result 
    pair <- DBIO.sequence(rawTypes.groupBy(_.projectId).toSeq.map(group => DBIO.successful(group))) 
    counts <- DBIO.sequence(pair.head._2.map(aType => sql"""select count(*) from messages where type_id = ${aType.id}""".as[Int])) 
} yield (pair.head._1, pair.head._2.zip(counts))).transactionally 
+0

Grazie! Sembra essere quello che stavo cercando. –