为什么.result
您需要应用.result 的原因是Slick 中查询(Query 类型)和操作(DBIO)之间的区别。
lists.filter 行本身就是一个查询。然而,第三行(update)是一个动作。如果您将.result 关闭,您的理解将在Query 和DBIO(操作)之间出现类型不匹配。
因为你要db.run 是 for 理解的结果,所以 for 理解需要产生一个 DBIO 操作,而不是一个查询。换句话说,将.result 放在那里是正确的做法,因为您正在构建一个要在数据库中运行的操作(即,为用户获取一些数据)。
您稍后将运行另一个操作以update 数据库。因此,总而言之,您使用for 将两个操作(两个可运行的 SQL 表达式)组合到一个 DBIO 中。那就是你产生的x,由db.run执行。
更好?
这对你有用,很好。
有少量重复。您可能会在第一行发现您的查询,非常类似于更新查询。您可以将其抽象为一个值:
val userLists = lists.filter(_.userId === userId)
这是一个查询。实际上,您可以更进一步,将查询修改为只选择 unknownWords 列:
val userUnknownWords = lists.filter(_.userId === userId).map(_.unknownWords)
我没有尝试编译它,但这会使您的代码类似于:
def update(userId: Long, unknownWords: List[String]) = {
val userUnknownWords = lists.filter(_.userId === userId).map(_.unknownWords)
db.run {
for {
y <- userUnknowlWords.result
words = y.flatMap(_.union(unknownWords)).distinct.toList
x <- userUnknownWords.update(words)
} yield x
}
鉴于您正在编写两个操作(选择和更新),您可以使用 DBIO.flatMap 代替 for 理解。你可能会发现它更清楚。或不。但这里有一个例子......
DBIO.flatMap 的参数需要是另一个动作。也就是说,flatMap 是一种对动作进行排序的方法。特别是,它是一种在使用数据库中的值时做到这一点的方法。
所以您可以将 for 理解替换为:
val action: DBIO[Int] =
userUnknowlWords.result.flatMap { currentWords =>
userUnknownWords.update(
currentWords.flatMap(_.union(unknownWords)).distinct.toList
)
}
(再次对没有编译上述内容表示歉意:我没有类型的详细信息,但希望这会给代码的工作方式带来一些启发)。
最后的action 是您可以传递给db.run 的那个。它返回更改的行数。