我正在尝试在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层中并保持数据库简单。
目前我最接近的是使用网络服务器时钟而不是数据库时钟:
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,这很容易。