【问题标题】:Elixir Ecto - Association with 3 or more tablesElixir Ecto - 与 3 个或更多表关联
【发布时间】:2021-06-10 15:40:46
【问题描述】:

如果我有profileitemlocation 表:

  • profile 有很多 location
  • item 有一个 location
  • profileitem 中的 location 不会重叠。

我应该如何设计location 表? 以下有效吗? location 属于 2 个表?

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要容易得多。代码中的抽象(如 Ecto 或 ORM)仅在它们使您与数据交互的工作变得更容易时才有用。我不确定我是否遵循您所说的“profileitem 中的location 不会重叠”,但我没有遵循配置文件和项目之间的关系。定义架构中的所有关系不会获得额外积分:我建议从您需要的查询开始,例如“一个位置所有项目的列表”,并建立实现它们所需的关系。

标签: elixir phoenix-framework ecto


【解决方案1】:

这是一个非常主观的问题,取决于您将如何使用locations 表中的数据。这通常是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_oneembeds_many 的嵌入式关联。如果您使用的是 Postgres,您甚至应该能够根据需要在 JSONB 列上创建索引。

【讨论】:

  • 其实这就是我现在正在做的事情。无论如何感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多