在 Slick 3 的事务中执行非数据库操作
Posted
技术标签:
【中文标题】在 Slick 3 的事务中执行非数据库操作【英文标题】:Executing non-database actions in a transaction in Slick 3 【发布时间】:2015-09-15 05:10:54 【问题描述】:我无法理解新的 Slick DBIOAction
API,文档中似乎没有很多示例。我使用的是 Slick 3.0.0,我需要执行一些数据库操作以及一些从数据库接收到的数据的计算,但是所有这些操作都必须在单个事务中完成。我正在尝试执行以下操作:
-
对数据库(
types
表)执行查询。
对查询结果进行一些聚合和过滤(无法在数据库上进行此计算)。
根据第 2 步的计算结果执行另一个查询(messages
表 - 由于某些限制,此查询必须使用原始 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
表中选择数据。
for
理解的第二行应该对结果进行一些分组和切片,导致Seq[(Option[String], Seq[String])]
for
理解的第三行必须对上一步中的每个元素执行一组查询,特别是,它必须对Seq[String]
中的每个值执行单个 SQL 查询。所以在第三行我构建了一个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
,因此代码无法编译。
【问题讨论】:
看看this example,看看对你有没有帮助 @FelipeAlmeida 谢谢,但这不是我所需要的。在这个例子中,所有的推导都是更新/删除/插入,它们的结果没有相互关联,也没有任何结果(所有左边的部分都是_
)。就我而言,我的一项操作与数据库完全无关,所有操作都返回用于其他理解或yield
的结果。
【参考方案1】:
试试这个方法:
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 3 的事务中执行非数据库操作的主要内容,如果未能解决你的问题,请参考以下文章