如何在 Slick 中的一系列数据库查询之间包含 scala 操作?
How can I include a scala operation between a sequence of database queries in Slick?
假设我有一个看起来像这样的模型:
case class User(username: String, dateOfBirth: Timestamp, lastSentGift: Timestamp)
假设我有一个合适的伴随 Slick 模式,Users
,我如何在一个事务中针对这个 table 执行多个查询,并在其间调用一个 scala 函数?
我看到 Slick 提供了 DBIOAction
和 DBIO.seq
允许在单个事务中组合多个数据库操作,但我不明白 if/how 我可以使用这些中间调用了一个 scala 函数。
例如,我想做这样的事情,但将所有内容都保存在一个事务中:
def prepareGiftFor(user: User): Timestamp = ???
val usersWithBirthdays = db.run(
Users.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
)
usersWithBirthdays
.map(user => (user.username, prepareGiftFor(user)))
.map { case (username, lastSentGift) =>
db.run(
Users.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
)
}
slick 的总体思路是尽可能延迟 db.run
调用。首选方法是使用 DBIOAction
个实例并将它们链接起来,就像我们使用 scala Future
或 Option
一样。
为此 DBIOAction
支持 map
和 flatMap
方法。 DBIOAction companion object also contains helper methods from
, successful
and failed
. With them you can construct DBIOAction
from primitive values. For more information check this section of slick documentation关于动作组合。
通过在 DBIOAction
个实例上调用 transactionally,可以在单个事务中 运行 所有 sql 查询。
您的示例可以重写为:
def prepareGiftFor(user: User): Timestamp = ???
def findUsersWithBirthdays(): DBIO[Seq[User]] = {
Users
.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
}
def updateUsers(users: Seq[User]): Seq[DBIO[Int]] = {
users
.map(user => (user.username, prepareGiftFor(user)))
.map {
Users
.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
}
}
db.run(
(for {
users <- findUsersWithBirthdays()
_ <- DBIO.sequience(updateUsers(users))
} yield ()).transactionaly
)
假设我有一个看起来像这样的模型:
case class User(username: String, dateOfBirth: Timestamp, lastSentGift: Timestamp)
假设我有一个合适的伴随 Slick 模式,Users
,我如何在一个事务中针对这个 table 执行多个查询,并在其间调用一个 scala 函数?
我看到 Slick 提供了 DBIOAction
和 DBIO.seq
允许在单个事务中组合多个数据库操作,但我不明白 if/how 我可以使用这些中间调用了一个 scala 函数。
例如,我想做这样的事情,但将所有内容都保存在一个事务中:
def prepareGiftFor(user: User): Timestamp = ???
val usersWithBirthdays = db.run(
Users.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
)
usersWithBirthdays
.map(user => (user.username, prepareGiftFor(user)))
.map { case (username, lastSentGift) =>
db.run(
Users.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
)
}
slick 的总体思路是尽可能延迟 db.run
调用。首选方法是使用 DBIOAction
个实例并将它们链接起来,就像我们使用 scala Future
或 Option
一样。
为此 DBIOAction
支持 map
和 flatMap
方法。 DBIOAction companion object also contains helper methods from
, successful
and failed
. With them you can construct DBIOAction
from primitive values. For more information check this section of slick documentation关于动作组合。
通过在 DBIOAction
个实例上调用 transactionally,可以在单个事务中 运行 所有 sql 查询。
您的示例可以重写为:
def prepareGiftFor(user: User): Timestamp = ???
def findUsersWithBirthdays(): DBIO[Seq[User]] = {
Users
.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
}
def updateUsers(users: Seq[User]): Seq[DBIO[Int]] = {
users
.map(user => (user.username, prepareGiftFor(user)))
.map {
Users
.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
}
}
db.run(
(for {
users <- findUsersWithBirthdays()
_ <- DBIO.sequience(updateUsers(users))
} yield ()).transactionaly
)