首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ecto条件上插入- Ecto.StaleEntryError

Ecto条件上插入- Ecto.StaleEntryError
EN

Stack Overflow用户
提问于 2021-06-29 16:53:51
回答 1查看 362关注 0票数 0

我正在努力完成智能插入,我将其定义为:

  • 如果db中没有相同id的模型,请插入
  • ,如果db中有相同id的条目,并且该条目是较新的(updated_at字段),则如果db中有相同id的条目,则不要更新
  • ,而该条目是旧的(updated_at字段),请更新

我看到repo.insert有将查询作为:on_conflict选项传递的选项。我决定编写最简约的源代码来满足我的需求。

代码语言:javascript
复制
update_query =
  from s in User,
     where: s.id == ^id,
     where: s.updated_at < ^updated_at,
     update: ^[set: Map.to_list(data)]

%User{}
|> Ecto.Changeset.change(data)
|> @repo.insert(conflict_target: :id, on_conflict: update_query)

只有在插入发生时,此代码才能工作。在冲突中,它会导致(Ecto.StaleEntryError) attempted to insert a stale struct:错误。我可以从where: s.id == ^id, where: s.updated_at < ^updated_at中删除update_query并删除此错误,但是这样就会丢失所需的updated_at检查。所需的postgres代码如下所示

代码语言:javascript
复制
INSERT INTO mytable (id, entry) VALUES (42, '2021-05-29 12:00:00')
ON CONFLICT (id)
   DO UPDATE SET entry = EXCLUDED.entry, ......
      WHERE mytable.entry < EXCLUDED.entry;
EN

回答 1

Stack Overflow用户

发布于 2021-06-29 17:58:43

我认为这样做可能更容易:

代码语言:javascript
复制
def smart_upsert(%{id: id, updated_at: updated_at} = data) do
    query =
      from u in User,
      where: u.id == ^id,
      where: u.updated_at < ^updated_at
     
    User
    |> Repo.get_by(query)
    |> case do
      nil ->
        %User{}

      existing_user ->
        existing_user
    end
    |> User.changeset(data)
    |> Repo.insert_or_update()
  end

诚然,这需要两个数据库操作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68182807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档