Scala 巧妙地使用db计算字段插入行并获取id
我正试图用Slick编写一个简单的活动记录风格的DAO,我发现这非常困难。 我想使用case类表示插入一行,使用数据库时间设置其“updated”列,并将新行值作为case类返回 i、 e.DAO应如下所示:Scala 巧妙地使用db计算字段插入行并获取id,scala,activerecord,slick,Scala,Activerecord,Slick,我正试图用Slick编写一个简单的活动记录风格的DAO,我发现这非常困难。 我想使用case类表示插入一行,使用数据库时间设置其“updated”列,并将新行值作为case类返回 i、 e.DAO应如下所示: class FooDao { def db: JdbcBackend.Database def insert(foo: FooRow): Future[FooRow] = { ??? } } // This class is auto-generated by sl
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,并且已创建
由数据库分配的时间戳
我还需要一个update
方法来更新foorw
,使用updated
列的数据库时钟并返回一个新的foorw
我尝试过的事情:
使用“返回”
我可以插入case类并使用返回的帮助程序获取生成的id,如中所述,即
这是可行的,但我看不到任何方法可以在insert语句中使用CURRENT\u 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
该项目看起来几乎符合我的需要,但它似乎不支持更新/创建的列
使用数据库默认值/触发器
我想我可以使用数据库默认值实现created
列,但是如何防止Slick在其insert语句中传入显式值并推翻它呢
我想我可以使用数据库触发器实现updated
列,但我更愿意将逻辑保留在Scala层中,并保持数据库的简单
使用web服务器时钟而不是DB时钟
目前最接近这一点的方法是使用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,这样做很容易。为什么会有带有
activerecord
的标签?这只是我的意见。。。Slick和Scala偏向于函数范式
,而像ActiveRecord这样的东西对大多数Scala程序员来说并不是很有用。不同的范式需要不同的方法。即使是制作比萨饼的最佳配方也不应该应用于制作汉堡。如果你正在寻找一种方法来支持像ActiveRecord这样的任意模型。。。您将需要同时使用scala宏和scala-reflection。所谓ActiveRecord,我的意思是“仅”,即“符合此模式的对象接口将包括诸如Insert、Update和Delete之类的函数,以及或多或少直接对应于基础数据库表中列的属性。”。我不认为这有什么不实用的地方。如果你有更合适的“披萨”食谱,我洗耳恭听。我不知道你这里所说的“任意模式”是什么意思。光滑的代码生成器在编译时之前从DB模式中创建类似“FooRow”的case类。不需要反射或宏。是。。。狡猾的代码gen做到了这一点。但是,对于从scrach开发的应用程序来说,这是正确的方法吗?这不应该是另一种方式吗(你用代码控制DB而不是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))
}
}