我在理解新的Slick DBIOAction
API时遇到了困难,文档中似乎没有太多的示例.我使用的是Slick 3.0.0,我需要执行一些DB操作,还需要对从数据库接收的数据进行一些计算,但所有这些操作都必须在单个事务中完成.我试着做以下几件事:
- 执行对数据库(
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
表中 Select 数据. - 理解
for
的第二行应该对结果进行分组和切片,结果是Seq[(Option[String], Seq[String])]
- 理解
for
的第三行必须对上一步中的每个元素执行一组查询,具体而言,它必须对Seq[String]
内的每个值执行单个SQL查询.所以在第三行,我构建了一个DBIOAction
的序列. - 第
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)))
^
我try 使用DBIO.successful
将第二行包装在DBIOAction
中,它应该将一个常量值提升到DBIOAction
一元:
(projectId, types) <- DBIO.successful(rawTypes.groupBy(_.projectId).toSeq.map(group => (group._1, group._2.slice(0, 10))))
但是在这段代码中,types
变量被推断为Any
,因此代码无法编译.