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

时间:2015-06-28 19:20:47

标签: database scala slick slick-3.0

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

  1. 执行对数据库的查询(types表)。
  2. 对查询结果进行一些聚合和过滤(此计算无法在数据库上完成)。
  3. 根据步骤2(messages表中的计算 - 执行另一个查询 - 由于某些限制,此查询必须使用原始SQL。)
  4. 将第2步和第3步中的数据加入内存中。
  5. 我希望步骤1和3中的查询在事务中执行,因为结果集中的数据必须一致。

    我试图以monadic连接方式做到这一点。这是我的代码的过度简化版本,但我甚至无法编译:

      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
    
    1. for理解的第一行选择types表中的数据。
    2. for理解的第二行应该对结果进行一些分组和切片,从而产生Seq[(Option[String], Seq[String])]
    3. for理解的第三行必须为上一步中的每个元素执行一组查询,特别是,它必须为Seq[String]中的每个值执行单个SQL查询。因此,在第三行中,我构建了一个DBIOAction s。
    4. 序列
    5. 第二步中的yield子句zip s types和第三步中的counts
    6. 然而,这种结构不起作用并且产生两个编译时错误:

      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)))
                                 ^
      

      我尝试使用DBIOAction将第二行包裹在DBIO.successful中,这应该将一个常量值提升到DBIOAction monad:

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

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

1 个答案:

答案 0 :(得分:16)

以这种方式尝试:

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