【问题标题】:Slick: update List in dbSlick:更新数据库中的列表
【发布时间】:2020-05-23 13:45:43
【问题描述】:

我在 Postgres 中的表架构如下:

我将 List[String] 存储在第 2 列中,并编写了使用新列表和旧列表的联合来更新此列表的工作方法:

  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() 链工作正常,是类型有问题吗?

【问题讨论】:

    标签: postgresql scala playframework slick


    【解决方案1】:

    为什么.result

    您需要应用.result 的原因是Slick 中查询(Query 类型)和操作(DBIO)之间的区别。

    lists.filter 行本身就是一个查询。然而,第三行(update)是一个动作。如果您将.result 关闭,您的理解将在QueryDBIO(操作)之间出现类型不匹配。

    因为你要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 的那个。它返回更改的行数。

    【讨论】:

    • 感谢您的详细解答!
    猜你喜欢
    • 2014-07-22
    • 2012-04-04
    • 1970-01-01
    • 2014-05-16
    • 2018-02-09
    • 2021-12-17
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    相关资源
    最近更新 更多