首页 > 解决方案 > 如何在 EntityFramework 中配置这种关系(1 -> many, plus 1 -> 0 or 1, no join table)

问题描述

我知道一个现实的选择是更改建议的 DB Schema;我也在追求这个选择。但是......我想知道是否可以设置 EF 以便它理解这种结构......


商业模式:

强制“一个 Bar 的特殊 Foo 必须与那个 Bar 相关联”的一致性是代码库的责任,而不是数据库的责任。

理想情况下,执行“一个 Bar 不能有多个特殊 Foo”的一致性是数据库的责任。


选择的数据库模型:

如上所述,我知道存在其他可能的结构,它们具有许多优点(尤其是“更容易在 EF 中配置”)。

CREATE TABLE [dbo].[Foo] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [BarId] INT NOT NULL,

    PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_Bar] FOREIGN KEY ([BarId]) REFERENCES [dbo].[Bar] ([Id])
);

CREATE TABLE [dbo].[Bar] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [SpecialFooId] INT NULL,

    PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_SpecialFoo] FOREIGN KEY ([SpecialFooId]) REFERENCES [dbo].[Foo] ([Id])
);

领域模型的当前猜测:

public class Foo
{
  public int Id { get; set; }

  // Props for easy 1-many relationship.
  public int BarId { get; set; }
  public virtual Bar Bar { get; set; }
}

public class Bar
{
  public int Id { get; set; }

  // Prop for easy 1-many relationship.
  public virtual ICollection<Foo> Foos { get; set; }

  // Props for hard 1-0..1 relationship.
  public int? SpecialFooId { get; set; }
  public virtual Foo SpecialFoo { get; set; }
}

我完全不确定这个域对象模型是否适合 EF,而且我也不知道如何配置它。

有谁知道如何使这项工作?

标签: c#entity-framework

解决方案


从根本上说,我无法完成这项工作的原因是上面描述的 DB 模型没有反映在上面描述的 C# 域对象模型中。

基于该数据库模型,单个 Foo 可能是多个Bar 的 SpecialFoo - 从 Bar 到 Foo 的 FK 不知道业务逻辑将确保实际上最多有一个 FK 指向任何给定的 Foo。

因此,类模型需要是:

public class Foo
{
  public int Id { get; set; }

  // Props for easy 1-many relationship.
  public int BarId { get; set; }
  public virtual Bar Bar { get; set; }

  //****** THE CHANGED BIT ******
  public ICollection<Bar> BarsForWhichThisIsTheSpecialFoo { get; set; }  
  //****** THE CHANGED BIT ******
}

public class Bar
{
  public int Id { get; set; }

  // Prop for easy 1-many relationship.
  public virtual ICollection<Foo> Foos { get; set; }

  // Props for hard 1-0..1 relationship.
  public int? SpecialFooId { get; set; }
  public virtual Foo SpecialFoo { get; set; }
}

然后正确的模型构建器咒语是:

    modelBuilder.Entity<Bar>()
        .HasMany(bar => bar.Foos)
        .WithRequired(foo => foo.Bar)
        .HasForeignKey(foo => foo.BarId);
    modelBuilder.Entity<Foo>()
        .HasMany(foo => foo.BarsForWhichThisIsTheSpecialFoo)
        .WithOptional(bar => bar.SpecialFoo)
        .HasForeignKey(bar => bar.SpecialFooId);

这表达了关系的变化 pov:根据 DB,Bars 并没有真正属于他们的 SpecialFoo ...... Foos 有一组他们是 Special 的 Bars。


推荐阅读