光滑如何插入带有db-calculated字段的行并获取id

时间:2016-10-27 07:06:54

标签: scala activerecord slick

我正在尝试在Slick中编写一个简单的Active Record样式DAO,我发现它很难。 我想使用case类表示插入一行,使用数据库时间设置其“updated”列,并将新行值作为case类返回。

即。 DAO应该是这样的:

class FooDao {
  def db: JdbcBackend.Database

  def insert(foo: FooRow): Future[FooRow] = {
    ???
  }
}

// This class is auto-generated by slick codegen
case class FooRow(
  id: Int,
  created: Option[java.sql.Timestamp]
  updated: Option[java.sql.Timestamp],
  x1: String,
  x2: String,
  x3: String)

我希望返回的FooRow对象具有由数据库分配的正确ID和created时间戳。

我还想要一个update方法来更新FooRow,使用updated列的数据库时钟并返回新的FooRow

我尝试过的事情:

使用“返回”

我可以插入case类并使用Slick 3.0 Insert and then get Auto Increment Value中描述的returning帮助器获取生成的id,即

class FooDao {
  def db: JdbcBackend.Database

  def insert(foo: FooRow): Future[FooRow] = {

    db.run((Foos returning Foos.map(_.id)) += fooRow)
        .map(id => fooRow.copy(id = id))
  }
}

这有效,但我看不到在insert语句中使用CURRENT_TIMESTAMP()以填充updated列的任何方法。类型不允许。

使用sqlu

我可以编写我想要使用sqlu的SQL,但是后来我看不到任何方法可以从Slick中获取生成的密钥。 JDBC API允许通过getGeneratedKeys(),但我无法在此处查看如何访问它:

class FooDao {
  def db: JdbcBackend.Database

  def insert(foo: FooRow): Future[FooRow] = {

    val sql: DBIO[Int] = sqlu"""
INSERT INTO  foos
            (created,
             updated,
             x1,
             x2,
             x3)
     VALUES (current_timestamp(),
             current_timestamp(),
             $foo.x1,
             $foo.x2,
             $foo.x3)
               """

    db.run(sql)
        .map(rowCount => ???)
  }
}

使用active-slick

https://github.com/strongtyped/active-slick项目看起来几乎是我需要的,但它似乎不支持更新/创建的列。

使用数据库默认值/触发器

我想我可以使用数据库默认值来实现created列,但是如何防止Slick在其insert语句中传入显式值并覆盖它?

我想我可以使用数据库触发器实现updated列,但我更喜欢将我的逻辑保留在Scala层中并保持数据库简单。

使用Web服务器时钟而不是DB时钟

目前我最接近的是使用网络服务器时钟而不是数据库时钟:

class FooDao {
  def db: JdbcBackend.Database

  def insert(foo: FooRow): Future[FooRow] = {

    val now = Some(Timestamp.from(Instant.now()))

    val toInsert = fooRow.copy(
       created = now,
       updated = now)

    db.run((Foos returning Foos.map(_.id)) += toInsert)
        .map(id => toInsert.copy(id = id))
  }
}

但是,我更倾向于为这些列使用数据库时钟,以防不同的Web服务器有不同的时间。

任何想法都会感激不尽。我强烈考虑放弃Slick并使用JOOQ,这很容易。

0 个答案:

没有答案