Slick update table 使用自动生成的主键

Slick update table with auto-generated primary key

我在 Scala 中有一个简单的案例 class,我使用自动生成的主键(序列号)映射到 DB2 table。 Slick DAO 对 INSERT 和 SELECT 工作正常,但对 UPDATE 抛出异常。

Slick 显示生成的 SQL,问题似乎在于它试图(也)更新主键列,而 DB2 不允许这样做。

这是 Slick 生成的 SQL 语句:

slick.basic.BasicBackend.action - [update "SOME_THING" set "RECORD_ID" = ?, "STATUS" = ? where "RECORD_ID" = ...]

因为我只是想更新 STATUS,这就是我想要的(并且应该有效):

slick.basic.BasicBackend.action - [update "SOME_THING" set                  "STATUS" = ? where "RECORD_ID" = ...]

如何修改我的代码以使更新生效?我可以用 DELETE+INSERT 替换 UPDATE,但是有更好的方法吗?

使用 Slick 3.3.3、Scala 2.12。

import slick.jdbc.DB2Profile.api._
import slick.lifted.ProvenShape

class SomethingTbl(tag: Tag, schemaName: String) extends Table[SomethingRec](tag, _schemaName = Some(schemaName), _tableName = "SOME_THING") {
  def record_id: Rep[Long] = column[Long]("RECORD_ID", O.PrimaryKey, O.AutoInc)

  def status: Rep[String] = column[String]("STATUS")

  override def * : ProvenShape[SomethingRec] = (record_id, status ) <> (SomethingRec.tupled, SomethingRec.unapply)
}

import akka.actor.ActorSystem
import slick.jdbc
import slick.jdbc.DB2Profile
import slick.sql.FixedSqlAction

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}

class SomethingDAO(schemaName: String)(implicit val system: ActorSystem) {

  import slick.jdbc.DB2Profile.api._

  lazy val someThings: TableQuery[SomethingTbl] =
    TableQuery[SomethingTbl](tag => new SomethingTbl(tag, schemaName))

  // Capture the DB-generated sequence number and return it
  private lazy val insertSomething: jdbc.DB2Profile.IntoInsertActionComposer[SomethingRec, SomethingRec] =
    someThings returning someThings.map(_.record_id) into ((rec, record_id) => rec.copy(record_id = record_id))

  private implicit val db: DB2Profile.backend.Database = Database.forConfig("slick-db2")

  def update(e: SomethingRec): Int = {
    val recordFut = db.run(updateSomething(e))
    val record = Await.result(recordFut, Duration.Inf)
    record
  }
  
  private def updateSomething(e: SomethingRec): FixedSqlAction[Int, NoStream, Effect.Write] = {
    someThings
      .filter(_.record_id === e.record_id)
      .update(e)
      // com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-798, SQLSTATE=428C9, SQLERRMC=RECORD_ID, DRIVER=4.19.26
  }
}

修改如下代码,生效

private def updateSomething(e: SomethingRec): FixedSqlAction[Int, NoStream, Effect.Write] = {
    val q = for {c <- someThings if c.record_id === e.record_id} yield c.status
    q.update(e.status)
}