我在Postgres中的表格架构如下:
我将List [String]存储在第二列中,并且编写了一种工作方法,该方法使用新列表和旧列表的并集来更新此列表:
def update(userId: Long, unknownWords: List[String]) = db.run {
for {
y <- lists.filter(_.userId === userId).result
words = y.map(_.unknownWords).flatMap(_.union(unknownWords)).distinct.toList
x <- lists.filter(_.userId === userId).map(_.unknownWords).update(words)
} yield x
}
有什么办法可以写得更好吗?也许问题是很愚蠢的,但是我不太明白为什么我应该将.result()应用于for表达式的第一行,所以3d行上的filter()。map()链工作正常,是类型有问题吗?
.result
您需要应用的原因.result
与Slick中查询(Query
类型)和操作(DBIO
)之间的差异有关。
就其本身而言,该lists.filter
行是一个查询。但是,第三行(update
)是一个动作。如果您.result
不进行理解,则aQuery
和DBIO
(action)之间的类型将不匹配。
因为您要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
}
假设您要组成两个动作(一个select和一个update),则可以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
。它返回已更改的行数。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句