在 Slick 3 的事务中执行非数据库操作
Executing non-database actions in a transaction in Slick 3
我无法理解新的 Slick DBIOAction
API,它在文档中似乎没有很多示例。我正在使用 Slick 3.0.0,我需要执行一些数据库操作,还需要对从数据库接收到的数据进行一些计算,但所有这些操作都必须在单个事务中完成。我正在尝试执行以下操作:
- 对数据库执行查询(
types
table)。
- 对查询结果做一些聚合和过滤(这个计算不能在数据库上做)。
- 根据第 2 步的计算执行另一个查询(
messages
table — 由于某些限制,此查询必须是原始的 SQL)。
- 在内存中连接第 2 步和第 3 步的数据。
我希望第 1 步和第 3 步中的查询在事务内执行,因为它们的结果集中的数据必须一致。
我尝试以单子连接方式执行此操作。这是我的代码的一个过于简化的版本,但我什至无法编译它:
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
- 第一行
for
理解从types
table中选择数据。
for
理解的第二行应该对结果进行一些分组和切片,从而产生 Seq[(Option[String], Seq[String])]
for
理解的第三行必须对上一步中的每个元素执行一组查询,特别是,它必须对每个值执行单个 SQL 查询Seq[String]
里面。所以在第三行我构建了一个 DBIOAction
s. 的序列
- 第二步的
yield
子句zip
s types
和第三步的counts
。
然而,这个构造不起作用并给出了两个编译时错误:
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)))
^
我试图通过使用 DBIO.successful
将第二行包装在 DBIOAction
中,这应该将一个常量值提升到 DBIOAction
monad 中:
(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))))
但在此代码中,types
变量被推断为 Any
,因此代码无法编译。
这样试试:
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
我无法理解新的 Slick DBIOAction
API,它在文档中似乎没有很多示例。我正在使用 Slick 3.0.0,我需要执行一些数据库操作,还需要对从数据库接收到的数据进行一些计算,但所有这些操作都必须在单个事务中完成。我正在尝试执行以下操作:
- 对数据库执行查询(
types
table)。 - 对查询结果做一些聚合和过滤(这个计算不能在数据库上做)。
- 根据第 2 步的计算执行另一个查询(
messages
table — 由于某些限制,此查询必须是原始的 SQL)。 - 在内存中连接第 2 步和第 3 步的数据。
我希望第 1 步和第 3 步中的查询在事务内执行,因为它们的结果集中的数据必须一致。
我尝试以单子连接方式执行此操作。这是我的代码的一个过于简化的版本,但我什至无法编译它:
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
- 第一行
for
理解从types
table中选择数据。 for
理解的第二行应该对结果进行一些分组和切片,从而产生Seq[(Option[String], Seq[String])]
for
理解的第三行必须对上一步中的每个元素执行一组查询,特别是,它必须对每个值执行单个 SQL 查询Seq[String]
里面。所以在第三行我构建了一个DBIOAction
s. 的序列
- 第二步的
yield
子句zip
stypes
和第三步的counts
。
然而,这个构造不起作用并给出了两个编译时错误:
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)))
^
我试图通过使用 DBIO.successful
将第二行包装在 DBIOAction
中,这应该将一个常量值提升到 DBIOAction
monad 中:
(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))))
但在此代码中,types
变量被推断为 Any
,因此代码无法编译。
这样试试:
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