我試圖在Ecto 2中創建一個自引用many_to_many
的關係。我跟着this blogpost到目前爲止工作。但試圖更新與Ecto.Changeset.put_assoc
的關聯總是會導致錯誤。我不明白爲什麼。Elixir Ecto 2:自引用many_to_many和Ecto.Changeset.put_assoc。怎麼樣?
這是設置:
首先遷移到創建用戶和聯繫人的關聯表(每個用戶可以擁有多個聯繫人這也是用戶):
# priv/repo/migrations/create_users_table.ex
defmodule MyApp.Repo.Migrations.CreateUsersTable do
use Ecto.Migration
def change do
create table(:users) do
add :username, :string
end
create unique_index(:users, [:username])
end
end
# priv/repo/migrations/create_contacts_table.ex
defmodule MyApp.Repo.Migrations.CreateContactsTable do
use Ecto.Migration
def change do
create table(:contacts) do
add :user_id, references(:users, on_delete: :nothing), primary_key: true
add :contact_id, references(:users, on_delete: :nothing), primary_key: true
timestamps()
end
end
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
This now works:
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
但我可以預加載關聯,我也可以手動創建關聯。所以我可以循環contact_ids並執行此操作:
result = user
|> Ecto.Changeset.change
|> Ecto.Changeset.put_assoc(:contacts, [Contact.changeset(%Contact{}, %{user_id: user_id, contact_id: contact_id})])
|> Repo.insert
我在做什麼錯在這裏?
是否有任何理由不僅僅使用['many_to_many'](https://hexdocs.pm/ecto/Ecto.Schema.html#many_to_many/3)? –
@JustinWood我只能引用[博客文章](http:// swanros。com/self-referencing-many-to-many-relationships-using-ecto /):'Elixir社區的一位成員告訴我Slack,這看起來更像是一對多的關係,我應該嘗試在我的應用中代表這種方式。 [...]在我的Phoenix應用程序的實際測試過程中,我注意到Ecto使用前一種關聯類型生成的查詢是錯誤的。如上所述將它從many_to_many切換到has_many,解決了問題 –