Elixir 外星人员为什么要预加载,为什么需要id

Elixir 外星人员为什么要预加载,为什么需要id,elixir,phoenix-framework,ecto,Elixir,Phoenix Framework,Ecto,当涉及到向现有模型添加新关联时,我对Ecto感到相当困惑。假设我有一些讨论板,用户可以在其中查看帖子,我有以下模型: schema "discussion_items" do many_to_many :likes, XXX.Tag, join_through: "discussion_items_likes" timestamps() end schema "likes" do belongs_to :user, XXX.User timestam

当涉及到向现有模型添加新关联时,我对Ecto感到相当困惑。假设我有一些讨论板,用户可以在其中查看帖子,我有以下模型:

  schema "discussion_items" do
    many_to_many :likes, XXX.Tag, join_through: "discussion_items_likes"
    timestamps()
  end

  schema "likes" do
    belongs_to :user, XXX.User
    timestamps()
  end
现在让我们假设我有一个现有的
DiscussionItem
,我想添加一个类似的关联,下面是我尝试的(简化的):

我发现这将在第一次正确创建Like和关联,但之后我会抱怨我需要一些id形式的附加信息:

您正在尝试更改关系:如XXX.DiscussionItem, 但缺少数据

如果您试图更新现有条目,请确保 在数据旁边包括条目主键(ID)

如果你和很多孩子有关系,至少相同的N 必须在更新时提供子项。默认情况下,不可能 孤立嵌入或关联记录,尝试这样做会导致 这是一条错误消息

下面是让我困惑的事情(有几个):

  • 此错误消息似乎表明,为了更新一个关联项,我需要提供一个包含所有项(包括已更改项)的更改集。这看起来很疯狂,所以我猜我看错了
  • 我不想更新likes关联--我想添加一个。这里的put_assoc是错误的选择吗
  • 我真的需要预先加载喜欢的东西来插入一个项目吗?即使在更新时,我也不想加载整个关联集合来更改一个
  • 我是否需要加载
    用户
    讨论项目
    以在此处添加类似项
  • 此错误消息似乎表明,为了更新一个关联项,我需要提供一个包含所有项(包括已更改项)的更改集。这看起来很疯狂,所以我猜我看错了

    是的,您需要预加载。从
    put\u assoc
    文档:

    此函数要求关联已预加载到变更集结构中。缺少的数据将调用关联上定义的:on_replace行为

    文档中给出的示例:

    # We can associate at any time post and tags together using changesets
    post
    |> Repo.preload(:tags) # Load existing data
    |> Ecto.Changeset.change() # Build the changeset
    |> Ecto.Changeset.put_assoc(:tags, [tag]) # Set the association
    |> Repo.update!
    
    我不想更新likes关联--我想添加一个。这里的put_assoc是错误的选择吗

    put_assoc
    只有在您不介意预加载所有现有的
    like
    的情况下才可以。如果您想避免预加载,那么a看起来是最好的选择

    我真的需要预先加载喜欢的东西来插入一个项目吗?即使在更新时,我也不想加载整个关联集合来更改一个

    为了方便使用
    put_assoc
    ,您需要预加载。 另一种方法是使用,允许您显式地插入/更新关系,而不依赖于任何一方的实体

    我是否需要加载User and Dicussion_项以在此处添加类似项

    不,你只需要身份证。 您可以使用参数中填充的
    user\u id
    字段构造
    Like
    变更集

    类似地,使用
    DiscussionItemLikes
    join模式,您可以设置
    like\u id
    discussion\u item\u id

    可能是在单个事务中创建
    %Like{}
    %DiscussionItemLike{}
    的干净方法

    Multi.new()
    |> Multi.insert(insert_like_changeset(params))
    |> Multi.insert(insert_discussion_item_like_changeset(params))
    |> Repo.transaction()
    

    似乎我发现答案是put_assoc需要所有现有项加上我想添加的一个通过更改集本身运行的项。这似乎效率很低,所以希望有更好的方法。为什么要使用
    many-to-many
    作为喜欢和讨论项目?like一次不应该只计算一个单独的讨论项目吗?我有几个我喜欢的东西,讨论项目只是其中之一,所以会有几个联接表。不管怎么说,这真的是离题了,我真正想知道的是如何在多对多关系中插入一个新项目而不加载世界,上面的例子不太重要,这可能是最好的做法。这有点冗长,但我认为一切变得如此简单是值得的。贾斯汀,我真的很遗憾我必须这么做,但这比另一种选择要好得多。
    Multi.new()
    |> Multi.insert(insert_like_changeset(params))
    |> Multi.insert(insert_discussion_item_like_changeset(params))
    |> Repo.transaction()