我有 2 个具有一对多关系的表/模式,假设有一个
Person
可以有多个 Animal
。然后每个动物都有人外键来实现这种关系。我将 Elixir 与 Ecto 一起使用,所以现在很简单,我已经
schema "persons" do
...
has_many :animals, Animal
end
schema "animals" do
...
belongs_to :person, Person
end
我想引入一个人最喜欢的动物的概念,每个人最多可以有 1 个最喜欢的动物(0 或 1)。当两个表之间已经存在一对多关系时,如何实现第二个关系?
我想到了两种替代解决方案,但都不是完美的。
不要引入一对一,但在 Animal 中还有另一个名为
favourite
的字段,具有 true 或 false。这是一个简单的解决方案,但缺乏数据库强制执行最多 1 个最喜欢的动物,因为数据库中同一个人的多个动物有可能拥有 favourite: true
,因此需要在业务逻辑中手动保留此约束并持续观察为了它。
引入一对一的关系。 Animal已经有了person_id_fkey,现在我需要将animal_id_fkey添加到Person中,表示该人最喜欢的动物。直觉告诉我那个人
has_one
最喜欢动物,但在Ecto中我们使用belongs_to
来引入外键,所以如下。
...
has_many :animals, Animal
belongs_to :favourite_animal, Animal
end
schema "animals" do
...
belongs_to :person, Person
has_one :person, Person <- this name must be different due to conflict
end
动词表明该人属于动物,但现实却截然不同。字段名称也存在歧义——人有最喜欢的动物,但是这个字段
has_one Person
应该如何命名?我不清楚,因为第二个场景中出现了越来越多的问题。
Ecto(或更普遍的 SQL)中解决此类双向外键关系的惯用方法是什么?
我无法立即测试它,因此我将其发布为答案只是为了格式化。如果它不适合您,请随意投反对票。
belongs_to/3
和适当的选项即可。
schema "persons" do
has_many :animals, Animal
has_one :favorite, Animal
end
schema "animals" do
belongs_to :person, Person, foreigh_key: :owner_id, references: :id
belongs_to :person, Person, foreign_key: :favorite_of_id, references: :id
end