Elixir Ecto - 与 3 个或更多表关联

Elixir Ecto - Association with 3 or more tables

如果我有 profileitemlocation table 其中:

locationtable应该怎么设计? 以下有效吗? 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_iditem_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 列上创建索引。