Elixir Ecto:如何存储关于多对多关系的元信息
Elixir Ecto: How to store meta information about a many-to-many relationship
假设我有模型 User
和 Organization
以及两者之间的多对多关系。我现在想添加有关两者之间关系的信息。例如 timestamps
和 position
。我该如何处理以及如何查询此信息?
我认为正确的方向是使用连接模式。按照 Ecto 文档,类似于:
defmodule UserOrganization do
use Ecto.Schema
@primary_key false
schema "users_organizations" do
field :position, :string # adding information on the position of the user within the organization
belongs_to :user, User
belongs_to :organization, Organization
timestamps # Added bonus, a join schema will also allow you to set timestamps
end
def changeset(struct, params \ %{}) do
struct
|> Ecto.Changeset.cast(params, [:user_id, :organization_id])
|> Ecto.Changeset.validate_required([:user_id, :organization_id])
# Maybe do some counter caching here!
end
end
defmodule User do
use Ecto.Schema
schema "users" do
many_to_many :organizations, Organization, join_through: UserOrganization
end
end
defmodule Organization do
use Ecto.Schema
schema "organizations" do
many_to_many :users, User, join_through: UserOrganization
end
end
# Then to create the association, pass in the ID's of an existing
# User and Organization to UserOrganization.changeset
changeset = UserOrganization.changeset(%UserOrganization{}, %{user_id: id, organization_id: id})
case Repo.insert(changeset) do
{:ok, assoc} -> # Assoc was created!
{:error, changeset} -> # Handle the error
end
现在如何在创建记录时设置 position
以及如何查询 timestamps
和 position
?
如果您想检索复合模式的 timestamps
和 position
,您可以在 User
和 Organization
上添加 has_many
关系, 像这样
defmodule Organization do
use Ecto.Schema
schema "organizations" do
many_to_many :users, User, join_through: UserOrganization
has_many :user_organizations, UserOrganization
end
end
然后您可以在检索 Organization
时 Repo.preload
关系 user_organizations
,您将可以使用 UserOrganization
的所有属性。
关于如何设置 position
你可以将它添加到变更集中并确保你在 UserOrganization
模式
上允许参数
def changeset(struct, params \ %{}) do
struct
|> Ecto.Changeset.cast(params, [:user_id, :organization_id, :position])
|> Ecto.Changeset.validate_required([:user_id, :organization_id])
# Maybe do some counter caching here!
end
changeset = UserOrganization.changeset(%UserOrganization{}, %{user_id: id, organization_id: id, position: position})
它应该对你很好。
假设我有模型 User
和 Organization
以及两者之间的多对多关系。我现在想添加有关两者之间关系的信息。例如 timestamps
和 position
。我该如何处理以及如何查询此信息?
我认为正确的方向是使用连接模式。按照 Ecto 文档,类似于:
defmodule UserOrganization do
use Ecto.Schema
@primary_key false
schema "users_organizations" do
field :position, :string # adding information on the position of the user within the organization
belongs_to :user, User
belongs_to :organization, Organization
timestamps # Added bonus, a join schema will also allow you to set timestamps
end
def changeset(struct, params \ %{}) do
struct
|> Ecto.Changeset.cast(params, [:user_id, :organization_id])
|> Ecto.Changeset.validate_required([:user_id, :organization_id])
# Maybe do some counter caching here!
end
end
defmodule User do
use Ecto.Schema
schema "users" do
many_to_many :organizations, Organization, join_through: UserOrganization
end
end
defmodule Organization do
use Ecto.Schema
schema "organizations" do
many_to_many :users, User, join_through: UserOrganization
end
end
# Then to create the association, pass in the ID's of an existing
# User and Organization to UserOrganization.changeset
changeset = UserOrganization.changeset(%UserOrganization{}, %{user_id: id, organization_id: id})
case Repo.insert(changeset) do
{:ok, assoc} -> # Assoc was created!
{:error, changeset} -> # Handle the error
end
现在如何在创建记录时设置 position
以及如何查询 timestamps
和 position
?
如果您想检索复合模式的 timestamps
和 position
,您可以在 User
和 Organization
上添加 has_many
关系, 像这样
defmodule Organization do
use Ecto.Schema
schema "organizations" do
many_to_many :users, User, join_through: UserOrganization
has_many :user_organizations, UserOrganization
end
end
然后您可以在检索 Organization
时 Repo.preload
关系 user_organizations
,您将可以使用 UserOrganization
的所有属性。
关于如何设置 position
你可以将它添加到变更集中并确保你在 UserOrganization
模式
def changeset(struct, params \ %{}) do
struct
|> Ecto.Changeset.cast(params, [:user_id, :organization_id, :position])
|> Ecto.Changeset.validate_required([:user_id, :organization_id])
# Maybe do some counter caching here!
end
changeset = UserOrganization.changeset(%UserOrganization{}, %{user_id: id, organization_id: id, position: position})
它应该对你很好。