如何插入一个对象并使用自动增量 ID 在单个 slick 事务中更新同一对象

How do I insert an object and use the auto-increment id to update the same object in a single slick transaction

我有以下形式的架构:

CREATE TABLE definitions (
  id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
  json LONGTEXT NOT NULL
);

json 是我想 return 给客户的,它应该包括自动生成的 id.

我想在单笔交易中执行以下操作:

  1. 插入一个新行,其中 json 不包含 id;从插入中获取自增id。
  2. 更新同一行并将 json 替换为包含 id.
  3. 的新对象

精巧的文档向我展示了如何获取自动增量 ID,但我不知道如何编写 query/insert 以在单个事务中执行这两个操作。

// TableQuery object for my table
class Definitions(driver: RelationalDriver, tag: Tag) extends ... {
  import driver.api._ 

  // implicit conversion for Definition
  private implicit val definitionToJson =
    MappedColumnType.base[Definition, String](
     { definition => definitionToJson(definition) },
     { json => definitionFromJson(json) }
  )

  def id: slick.lifted.Rep[Long] =
    column[Long](
      "id", 
      ColumnOption.PrimaryKey,
      ColumnOption.AutoInc
    )

  def json: slick.lifted.Rep[Definition] =     
    column[Definition]("json")

  override def * = (
    id,
    json
  ) <> (DefinitionRow.tupled, DefinitionRow.unapply)
}

class Dao {

  // ...

  // operation 1: insert row, and get back auto-increment id
  // definitions is an instance of above
  val op1 = (definitions returning definitions.map(_.id)) += json

  // operation 2: find the inserted row and update the object
  val op2 = op1.flatMap(insertId =>
    definitions.filter(_.id === insertId)
               .map(_.json)
               .update(updatedJson(insertId))

  // run both in a transaction
  db.run(op2.transactionally)
}

op2 拒绝编译。

[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your *  
  projection. Or you use an unsupported type in a Query
  (e.g. scala List).
[error]   Required level: slick.lifted.FlatShapeLevel
[error]      Source type: slick.lifted.Rep[Definition]
[error]    Unpacked type: T
[error]      Packed type: G
[error]       val op2 = op1.flatMap(autoIncId =>   
                correlationDefinitionSlick.filter(_.id ===
                autoIncId.get).map(_.json).update(json))

老实说,我不明白为什么它不能映射请求的类型。

编辑:我通过在我的 DAO 中重新定义隐式转换来实现上述功能,但我不明白为什么我需要这样做。

Slick Queries require implicit mappings in scope

您遇到此编译器错误是因为您将 table 中的隐式定义映射声明为私有的,并且无法访问以查询您使用定义的位置。

将您的代码移至容器 class 并在 Table

之外声明隐式平滑映射
class Container(driver: RelationalDriver) {

      import driver.api._ 
    // implicit conversion for Definition
      private implicit val definitionToJson =
        MappedColumnType.base[Definition, String](
         { definition => definitionToJson(definition) },
         { json => definitionFromJson(json) }
      )

        class Definitions(driver: RelationalDriver, tag: Tag) extends ... {



      def id: slick.lifted.Rep[Long] =
        column[Long](
          "id", 
          ColumnOption.PrimaryKey,
          ColumnOption.AutoInc
        )

      def json: slick.lifted.Rep[Definition] =     
        column[Definition]("json")

      override def * = (
        id,
        json
      ) <> (DefinitionRow.tupled, DefinitionRow.unapply)
    }

    class Dao {

      // ...

      // operation 1: insert row, and get back auto-increment id
      // definitions is an instance of above
      val op1 = (definitions returning definitions.map(_.id)) += json

      // operation 2: find the inserted row and update the object
      val op2 = op1.flatMap(insertId =>
        definitions.filter(_.id === insertId)
                   .map(_.json)
                   .update(updatedJson(insertId))

      // run both in a transaction
      db.run(op2.transactionally)
    }

}