在 Slick 3.0 中,如何简化嵌套的 `db.run`?
In Slick 3.0, how to simplify nested `db.run`?
我使用的是 Slick 3.0,下面是我的代码:
def registerMember(newMember: TeamMember): Future[Long] = {
db.run(
teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
).flatMap {
case None => Future(-1)
case _ => db.run(
(teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord
)
}
}
这看起来不错。但是当回调的层数增加时,代码可能会变得难以阅读。我尝试使用 for-expression
或 andThen
.. 来简化代码。但是由于模式匹配部分,我只能使用 flatMap
来实现这个..
有没有人知道如何重构它?
我认为 for comprehension 在这里应该没问题,您只需要对第一个 Future
的结果中的 Option
进行条件处理。像这样的东西应该可以工作(注意我没有编译检查这个):
def registerMember(newMember: TeamMember): Future[Long] = {
for{
r1Opt <- db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
r2 <- r1Opt.fold(Future.successful(-1L))(r1 => db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord)
} yield r2
}
您可以在 fold
的右侧看到我可以访问第一个 Future
的结果,如果它是 Some
(如 r1
).
我什至会更进一步,为 for comprehension 的步骤创建单独的方法来清理内容,如下所示:
def registerMember(newMember: TeamMember): Future[Long] = {
def findMember =
db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
def addMember(r1Opt:Option[TeamMember]) = {
r1Opt.fold(Future.successful(-1L)){r1 =>
db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) +=
newMember.toTeamRecord)
}
}
for{
r1Opt <- findMember
r2 <- addMember(r1Opt)
} yield r2
}
当查询跨越两个 table 时,在 Slick 3.0 中简化嵌套 db.runs 的另一种方法可能是将查询合并为一个查询。 Joining and Zipping。但是,OP 似乎在同一个 table 上有嵌套查询的情况比较少见,因此这种方法在这种特殊情况下可能没有帮助。
val query = slickLoginInfos join slickUserLoginInfos on
((l,ul) => l.id === ul.loginInfoId)
db.run((for { (l, ul) <- query } yield (ul)).result.headOption)
我使用的是 Slick 3.0,下面是我的代码:
def registerMember(newMember: TeamMember): Future[Long] = {
db.run(
teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
).flatMap {
case None => Future(-1)
case _ => db.run(
(teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord
)
}
}
这看起来不错。但是当回调的层数增加时,代码可能会变得难以阅读。我尝试使用 for-expression
或 andThen
.. 来简化代码。但是由于模式匹配部分,我只能使用 flatMap
来实现这个..
有没有人知道如何重构它?
我认为 for comprehension 在这里应该没问题,您只需要对第一个 Future
的结果中的 Option
进行条件处理。像这样的东西应该可以工作(注意我没有编译检查这个):
def registerMember(newMember: TeamMember): Future[Long] = {
for{
r1Opt <- db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
r2 <- r1Opt.fold(Future.successful(-1L))(r1 => db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord)
} yield r2
}
您可以在 fold
的右侧看到我可以访问第一个 Future
的结果,如果它是 Some
(如 r1
).
我什至会更进一步,为 for comprehension 的步骤创建单独的方法来清理内容,如下所示:
def registerMember(newMember: TeamMember): Future[Long] = {
def findMember =
db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
def addMember(r1Opt:Option[TeamMember]) = {
r1Opt.fold(Future.successful(-1L)){r1 =>
db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) +=
newMember.toTeamRecord)
}
}
for{
r1Opt <- findMember
r2 <- addMember(r1Opt)
} yield r2
}
当查询跨越两个 table 时,在 Slick 3.0 中简化嵌套 db.runs 的另一种方法可能是将查询合并为一个查询。 Joining and Zipping。但是,OP 似乎在同一个 table 上有嵌套查询的情况比较少见,因此这种方法在这种特殊情况下可能没有帮助。
val query = slickLoginInfos join slickUserLoginInfos on
((l,ul) => l.id === ul.loginInfoId)
db.run((for { (l, ul) <- query } yield (ul)).result.headOption)