在Slick 3中的事务中执行非数据库操作

Ser*_*nin 25 database scala slick slick-3.0

我无法理解新的Slick DBIOActionAPI,它在文档中似乎没有很多例子.我正在使用Slick 3.0.0,我需要执行一些数据库操作以及从数据库接收的数据的一些计算,但所有这些操作都必须在单个事务中完成.我正在尝试执行以下操作:

  1. 对数据库(types表)执行查询.
  2. 对查询结果进行一些聚合和过滤(无法在数据库上进行此计算).
  3. 根据步骤2中的计算执行另一个查询(该messages表 - 由于某些限制,此查询必须在原始SQL中).
  4. 将步骤2和3中的数据加入内存中.

我希望步骤1和3中的查询在事务内执行,因为结果集中的数据必须一致.

我试图用monadic join样式做到这一点.这是我的代码的过度简化版本,但我甚至无法编译:

  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
Run Code Online (Sandbox Code Playgroud)
  1. 第一行for理解选择types表中的数据.
  2. for理解的第二行应该对结果进行一些分组和切片,从而产生一个Seq[(Option[String], Seq[String])]
  3. 第三行for理解必须为上一步中的每个元素执行一组查询,特别是,它必须为每个内部值执行单个SQL查询Seq[String].所以在第三行我构建了一个DBIOActions 序列.
  4. yield子句zip小号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)))
                           ^
Run Code Online (Sandbox Code Playgroud)

我试图DBIOAction通过使用包装第二行DBIO.successful,这应该将一个常量值提升到DBIOActionmonad中:

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

但是在这段代码中,types变量被推断为Any,并且代码因此而无法编译.

Bha*_*vya 18

试试这种方式:

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
Run Code Online (Sandbox Code Playgroud)