【问题标题】:Scala Slick update column valueScala Slick 更新列值
【发布时间】:2017-06-13 18:12:35
【问题描述】:

我在 Play 中使用 Slick,但在尝试更新列值时遇到了一些问题,因为它没有被更新,尽管我没有收到任何错误。

我有一列告诉我是否选择了给定的行。我想要做的是获取当前选定的值(存储在 DB 列中),然后更新同一列以具有相反的值。目前(经过多次不成功的尝试)我有以下代码可以编译和运行,但在幕后没有任何反应:

val action = listItems.filter(_.uid === uid).map(_.isSelected).result.map { selected =>
      val isSelected = selected.head
      println(s"selected before -> $isSelected")
      val q = for {li <- listItems if li.uid === uid} yield li.isSelected
      q.update(!isSelected)
    }

db.run(action)

我做错了什么(我是新手,所以这可能根本没有任何意义!)

【问题讨论】:

  • 我写了一个语法更好看的答案。但简而言之,您的代码的问题是result.map 必须是result.flatMap。如果记录不存在,val isSelected = selected.head 也可能会抛出异常。所以考虑使用selected.headOption 代替我在答案中写的
  • 我已经尝试了您在上面评论中提到的更改并且它有效!我只是不明白为什么flatMap 与map 相比会有所不同。我也更喜欢你的回答,但我似乎无法让它发挥作用
  • map 和 flatMap 是两个非常不同的东西,而不仅仅是在您的示例中。他们的定义可以追溯到范畴论。您应该阅读该内容,但基本上以示例为例,如果您将Int =&gt; List[String] 的函数映射到List[Int],您将得到List[List[String]],但如果您将相同的函数平面映射到同一个列表,您将得到@987654331 @ 将其转换为您的示例,如果您将另一个 DBIOAction[T] 平映射到您的拳头 DBIOAction[G] 上,则结果是单个 DBIOAction[T],这是您想要的,并且是两个动作的组合。

标签: database scala playframework slick


【解决方案1】:

这需要单独的操作:一次读取,然后是更新。 Slick 允许以简洁的方式组合动作:

val targetRows = listItems.filter(_.uid === uid).map(_.isSelected)
val actions = for {
  booleanOption <- targetRows.result.headOption
  updateActionOption = booleanOption.map(b => targetRows.update(!b))
  affected <- updateActionOption.getOrElse(DBIO.successful(0))
} yield affected

db.run(actions)

更新:

顺便说一句,RDBMS 通常有助于在一次数据库往返中执行更新的构造,例如将布尔列更新为相反的值,而无需先读取它并手动否定它。这在 mysql 中看起来像这样:

UPDATE `table` SET `my_bool` = NOT my_bool

但据我所知,高级 slick api 不支持这种结构。因此在您的情况下需要两个单独的数据库操作。如果有人证明我错了,我本人将不胜感激。

【讨论】:

  • 好吧,代码编译和运行没有打嗝,但是当我去检查值仍然没有更新时......它是否可能与我正在使用的 DBMS(H2对于开发环境)?
  • 我目前无法重现该错误,但如果您在插入后在同一脚本中检查数据库的结果,则应该没有问题。我在这里写了基本相同的脚本。您可以删除.take(1) 位并再次运行它吗?还要确保在插入后使用所指出的 flatMap 构造或使用 Await.result 完成检查
  • 在您的示例和我的回答中,执行查询的返回结果也是一个整数,表示受影响的行数。我的是 0 而你的是 1 吗?
  • 它与.take(1)part 相关。我已经删除了它,它现在可以工作了。在进行您所说的检查时,takepart 不会打印任何内容,但在删除时会打印 1。我的印象是参加者删除了第一行,然后只在该行上做某事,对吧?通过删除它,如果第一个地图返回多行,它不会更新所有行吗?无论如何,您能否更新您的答案,以便我将其标记为正确?谢谢!
  • .take(1) 等于 mysql Limit 1 并且与我的假设相矛盾,它会跳过第一行会受到影响,而不是将效果限制在一行。所以我不好。我更新了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多