如何在Slick中的一系列数据库查询之间包含scala操作?

时间:2018-10-29 06:59:40

标签: postgresql scala slick

假设我有一个看起来像这样的模型:

case class User(username: String, dateOfBirth: Timestamp, lastSentGift: Timestamp)

假设我有一个适当的随附Slick模式Users,如何在事务中对该表执行多个查询,并在两者之间调用scala函数?

我已经看到Slick提供了DBIOActionDBIO.seq来允许在单个事务中组合多个数据库操作,但是我不知道我是否/如何将它们与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)
    )
  }

1 个答案:

答案 0 :(得分:1)

光滑的一般想法是尽可能延迟db.run通话。首选方式是使用DBIOAction实例并像使用scala FutureOption一样链接它们。

为此,DBIOAction支持mapflatMap方法。 DBIOAction伴随对象还包含辅助方法fromsuccessfulfailed。使用它们,您可以从原始值构造DBIOAction。有关更多信息,请查看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
)