Elixir Ecto - 与 3 个或更多表关联
Elixir Ecto - Association with 3 or more tables
如果我有 profile
、item
、location
table 其中:
profile
有很多 location
.
item
有一个 location
.
location
在 profile
和 item
中不会重叠。
location
table应该怎么设计?
以下有效吗? location
属于 2 tables?
schema "profiles" do
...
has_many :location, Location
end
schema "items" do
...
has_one :location, Location
end
schema "locations" do
...
belongs_to :profile, Profile
belongs_to :item, Item
end
还是应该有 2 location
tables?
这是一个非常主观的问题,取决于您将如何使用 locations
table 中的数据。这通常是 polymorphic associations in Ecto 的推荐方法,具有额外的数据库约束,强制 profile_id
或 item_id
之一始终设置在位置记录上。
defmodule MyApp.Repo.Migrations.CreateLocations do
use Ecto.Migration
def change do
create table(:locations) do
add :profile_id, references(:profiles, on_delete: :delete_all)
add :item_id, references(:items, on_delete: :delete_all)
end
create constraint(:locations, :at_least_one_ref, check: "profile_id is not null or item_id is not null")
create index(:locations, [:profile_id, :item_id])
end
end
然后在变更集中,您可以验证此约束:
def changeset(location, attrs) do
location
|> cast(attrs, [:profile_id, :item_id])
|> check_constraint(:profile_id, name: :at_least_one_ref)
end
另一种非常特定于 Ecto 的方法,但效果非常好,特别是因为您提到配置文件和项目之间没有位置重叠是使用 embeds_one and embeds_many 使用嵌入式关联。如果您使用的是 Postgres,如果需要,您甚至应该能够在 JSONB 列上创建索引。
如果我有 profile
、item
、location
table 其中:
profile
有很多location
.item
有一个location
.location
在profile
和item
中不会重叠。
location
table应该怎么设计?
以下有效吗? location
属于 2 tables?
schema "profiles" do
...
has_many :location, Location
end
schema "items" do
...
has_one :location, Location
end
schema "locations" do
...
belongs_to :profile, Profile
belongs_to :item, Item
end
还是应该有 2 location
tables?
这是一个非常主观的问题,取决于您将如何使用 locations
table 中的数据。这通常是 polymorphic associations in Ecto 的推荐方法,具有额外的数据库约束,强制 profile_id
或 item_id
之一始终设置在位置记录上。
defmodule MyApp.Repo.Migrations.CreateLocations do
use Ecto.Migration
def change do
create table(:locations) do
add :profile_id, references(:profiles, on_delete: :delete_all)
add :item_id, references(:items, on_delete: :delete_all)
end
create constraint(:locations, :at_least_one_ref, check: "profile_id is not null or item_id is not null")
create index(:locations, [:profile_id, :item_id])
end
end
然后在变更集中,您可以验证此约束:
def changeset(location, attrs) do
location
|> cast(attrs, [:profile_id, :item_id])
|> check_constraint(:profile_id, name: :at_least_one_ref)
end
另一种非常特定于 Ecto 的方法,但效果非常好,特别是因为您提到配置文件和项目之间没有位置重叠是使用 embeds_one and embeds_many 使用嵌入式关联。如果您使用的是 Postgres,如果需要,您甚至应该能够在 JSONB 列上创建索引。