【问题标题】:The correct way to swap values that have a unique constraints with Ecto?与 Ecto 交换具有唯一约束的值的正确方法?
【发布时间】:2017-07-07 09:52:07
【问题描述】:

我需要交换具有唯一约束的值。我正在尝试使用如下所示的 update_all 函数。

from(e in Episode, where: e.show_id == ^id, update: [set: [position: fragment("position + 1")]])
|> Repo.update_all([])

当使用这个时,由于位置重复,我得到一个错误:

ERROR (unique_violation): duplicate key value violates unique constraint "position_show_id_index"
table: episodes
constraint: position_show_id_index
Key ("position", show_id)=(2, 27) already exists.

如何同时交换这些位置值?

【问题讨论】:

  • 我认为一种方法是使用事务并首先检查并可能删除以前的记录,然后插入新记录。

标签: postgresql elixir phoenix-framework ecto


【解决方案1】:

一般来说,在 SQL 中交换唯一索引值没有“好”的方法。

Two known solutions 正在 1) 删除并重新插入行,或 2) 将行更新为另一个占位符值,然后再更新它们。

您可以在 Ecto 中采用类似的方法,如下所示:

解决方案 1:

episode = Repo.get(Episode, id)
next_episode = Repo.get_by(Episode, position: episode.position + 1)

if next_episode, do: Repo.delete(next_episode)

episode
|> Episode.changeset(%{position: episode.position + 1})
|> Repo.update()

if next_episode do
  Repo.insert(%Episode{next_episode | position: episode.position})
end

解决方案 2: (您需要选择一些“不可能”的值作为占位符。例如,如果位置必须为正,则可以使用负数)

episode = Repo.get(Episode, id)
next_episode = Repo.get_by(Episode, position: episode.position + 1)

if next_episode do
  next_episode
  |> Episode.changeset(%{position: -1})
  |> Repo.update()
end

episode
|> Episode.changeset(%{position: episode.position + 1})
|> Repo.update()

if next_episode do
  next_episode
  |> Episode.changeset(%{position: episode.position})
  |> Repo.update()
end

如果您有任何引用 Episode 的外键约束,则第二种解决方案可能更可取。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-18
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    • 2018-11-09
    • 2014-01-12
    • 2021-09-13
    相关资源
    最近更新 更多