更新 Ecto 变更集关联

Update Ecto Changeset Assocations

我有一个具有 has_many 关联的 Ecto 模式设置。我希望能够动态 add/remove 关联到它,保持初始关联。

我尝试使用 Ecto.Changeset.put_assoc/4 并且它在加载初始关联时有效,但是每个后续调用都会覆盖初始关联。

change_one = Changeset.put_assoc(changeset, :foo_assocs, [%{index: 1}])
...
foo_assocs: [
  #Ecto.Changeset<
    action: :insert,
    changes: %{index: 1},
    errors: [],
    data: #Linker.CustomForms.FooAssoc<>,
    valid?: true
  >
]
...

然后如果我再次调用它并添加另一条关联记录:

change_two = Changeset.put_assoc(changeset_one, :foo_assocs, [%{index: 2}])
...
foo_assocs: [
  #Ecto.Changeset<
    action: :insert,
    changes: %{index: 2},
    errors: [],
    data: #Linker.CustomForms.FooAssoc<>,
    valid?: true
  >
]
...

我的第一条记录被覆盖了。

这是 put_assoc/4 as it is intended to work with full data set. Actually your question is described very well in Ecto docs: https://hexdocs.pm/ecto/Ecto.Changeset.html#put_assoc/4-example-adding-a-comment-to-a-post

的预期行为

A map or keyword list can be given to update the associated data as long as they have matching primary keys. For example, put_assoc(changeset, :comments, [%{id: 1, title: "changed"}]) will locate the comment with :id of 1 and update its title. If no comment with such id exists, one is created on the fly. Since only a single comment was given, any other associated comment will be replaced.

因此,您可以将现有数据与新数据合并并使用 put_assoc/4,或者您可以像下面的示例一样处理您的单一关联,其中您从 child

设置关联
changeset = %__MODULE__{} |> has_many(:foo_assoc, [%{index: 1}])

%FooChild{index: 2}
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:parent, changeset)
|> Repo.insert!()

但我建议阅读上面的 link 以更详细地说明如何使用 put_assoc/4has_many