Elixir-Exto 2:自引用多对多和exto.Changeset.put\u assoc.如何?
我正在尝试在《星外2》中创建一个自引用的Elixir-Exto 2:自引用多对多和exto.Changeset.put\u assoc.如何?,elixir,ecto,Elixir,Ecto,我正在尝试在《星外2》中创建一个自引用的many\u-to\u-many关系。我关注了blogpost,到目前为止它一直在运行。但是,尝试更新与exto.Changeset.put_assoc的关联总是会导致错误。我不明白为什么 这是设置: defmodule MyApp.User do use MyApp.Web, :model alias MyApp.Contact schema "users" do field :username, :string # A
many\u-to\u-many
关系。我关注了blogpost,到目前为止它一直在运行。但是,尝试更新与exto.Changeset.put_assoc
的关联总是会导致错误。我不明白为什么
这是设置:
defmodule MyApp.User do
use MyApp.Web, :model
alias MyApp.Contact
schema "users" do
field :username, :string
# Add the many-to-many association
has_many :_contacts, MyApp.Contact
has_many :contacts, through: [:_contacts, :contact]
timestamps
end
# Omitting changesets
end
defmodule MyApp.Contact do
use MyApp.Web, :model
alias MyApp.User
schema "contacts" do
belongs_to :user, User
belongs_to :contact, User
end
end
schema "users" do
field :username, :string
many_to_many :contacts, MyApp.User, join_through: MyApp.Contact, join_keys: [user_id: :id, contact_id: id]
timestamps
end
首先,迁移以创建用户和联系人的关联表(每个用户都可以有多个联系人,这些联系人也是用户):
现在型号:
defmodule MyApp.User do
use MyApp.Web, :model
alias MyApp.Contact
schema "users" do
field :username, :string
# Add the many-to-many association
has_many :_contacts, MyApp.Contact
has_many :contacts, through: [:_contacts, :contact]
timestamps
end
# Omitting changesets
end
defmodule MyApp.Contact do
use MyApp.Web, :model
alias MyApp.User
schema "contacts" do
belongs_to :user, User
belongs_to :contact, User
end
end
schema "users" do
field :username, :string
many_to_many :contacts, MyApp.User, join_through: MyApp.Contact, join_keys: [user_id: :id, contact_id: id]
timestamps
end
现在可以这样做了:
user = Repo.get!(User, 1) |> Repo.preload :contacts
user.contacts
现在,我试图解析一个逗号分隔的ID字符串,获取用户,将其转换为变更集,并将其作为联系人附加到另一个用户
# Parse string and get list of ids
contact_ids = String.split("2, 3, 4", ",") |> Enum.map(&String.trim/1)
# Get contacts
contacts = Enum.map(contact_ids, fn(id) ->
Repo.get! User, id
end)
# Turn them into changesets
contact_changesets = Enum.map(contacts, &Ecto.Changeset.change/1)
# Update the associations
result = user |> Ecto.Changeset.change
|> Ecto.Changeset.put_assoc(:contacts, contact_changesets)
|> Repo.update
我得到的错误是
** (ArgumentError) cannot put assoc `contacts`, assoc `contacts` not found. Make sure it is spelled correctly and properly pluralized (or singularized)
(ecto) lib/ecto/changeset.ex:568: Ecto.Changeset.relation!/4
(ecto) lib/ecto/changeset.ex:888: Ecto.Changeset.put_relation/5
但是我可以预加载关联,也可以手动创建关联。所以我可以在联系人ID上循环并执行以下操作:
result = user
|> Ecto.Changeset.change
|> Ecto.Changeset.put_assoc(:contacts, [Contact.changeset(%Contact{}, %{user_id: user_id, contact_id: contact_id})])
|> Repo.insert
我做错了什么?我无法用自己的联想重现这个问题。我有一种感觉,您可能在某个时候正在使用
%MyApp.Contact{}
而不是%MyApp.User{}
?你能检查一下并报告吗
我注意到(但不会产生此错误):您正在尝试将MyApp.User
更改集放入:contacts
关联中,该关联需要MyApp.Contact
更改集
你可以尝试使用。您可以确保使用它返回MyApp.User
,这样就不会出现像这样的边缘情况。无论如何,它是专门为这些类型的协会而设计的
MyApp.User模式:
defmodule MyApp.User do
use MyApp.Web, :model
alias MyApp.Contact
schema "users" do
field :username, :string
# Add the many-to-many association
has_many :_contacts, MyApp.Contact
has_many :contacts, through: [:_contacts, :contact]
timestamps
end
# Omitting changesets
end
defmodule MyApp.Contact do
use MyApp.Web, :model
alias MyApp.User
schema "contacts" do
belongs_to :user, User
belongs_to :contact, User
end
end
schema "users" do
field :username, :string
many_to_many :contacts, MyApp.User, join_through: MyApp.Contact, join_keys: [user_id: :id, contact_id: id]
timestamps
end
我添加了join\u keys
选项,因为我认为没有它,在这种情况下,Ecto可能会感到困惑。我建议你试试有没有
使用
many\u to\u many
您可以将MyApp.User
变更集直接插入:contacts
关联中,这似乎就是你想要做的。你有什么理由不只是使用它吗?@JustinWood我只能引用:一个Elixir社区的成员在Slack上告诉我,这看起来更像是一对多的关系,我应该尝试在我的应用程序中这样表示。[…]在我的Phoenix应用程序的实际测试中,我注意到,使用前一个关联类型生成的查询是错误的。将其从“多”切换到“多到”后,修复了上述问题。