database - Ejecutar acciones que no son de base de datos en una transacción en Slick 3
scala slick-3.0 (1)
Inténtalo de esta manera:
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
Estoy teniendo problemas para entender la nueva API Slick DBIOAction
, que no parece tener muchos ejemplos en la documentación. Estoy utilizando Slick 3.0.0, y necesito ejecutar algunas acciones de la base de datos y también algunos cálculos con los datos recibidos de la base de datos, pero todas esas acciones deben realizarse dentro de una sola transacción. Estoy tratando de hacer lo siguiente:
- Ejecutar una consulta a la base de datos (la tabla de
types
). - Realice algunas agregaciones y filtre los resultados de la consulta (este cálculo no se puede realizar en la base de datos).
- Ejecute otra consulta, según los cálculos del paso 2 (la tabla de
messages
, debido a algunas limitaciones, esta consulta debe estar en SQL sin formato). - Unir los datos de los pasos 2 y 3 en la memoria.
Quiero que las consultas de los pasos 1 y 3 se ejecuten dentro de una transacción, ya que los datos de sus conjuntos de resultados deben ser coherentes.
He tratado de hacer esto en un estilo de unión monádica. Aquí hay una versión muy simplificada de mi código, pero ni siquiera puedo compilarlo:
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
- La primera fila de
for
comprensión selecciona los datos de la tabla detypes
. - Se supone que la segunda fila de
for
comprensión hace un poco de agrupación y corte de los resultados, dando como resultado unSeq[(Option[String], Seq[String])]
- La tercera fila de
for
comprensión tiene que ejecutar un conjunto de consultas para cada elemento del paso anterior, en particular, tiene que ejecutar una única consulta SQL para cada uno de los valores dentro deSeq[String]
. Así que en la tercera fila construyo una secuencia deDBIOAction
s. - La cláusula de
yield
zip
lostypes
s desde el segundo paso ycounts
desde el tercer paso.
Esta construcción, sin embargo, no funciona y da dos errores de tiempo de compilación:
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)))
^
He intentado envolver la segunda línea en una DBIOAction
utilizando DBIO.successful
, que se supone eleva un valor constante en la mónada DBIOAction
:
(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))))
Pero en este código se infiere que la variable de types
es Any
, y el código no se compila debido a eso.