【问题标题】:How can I configure this relationship in EntityFramework (1 -> many, plus 1 -> 0 or 1, no join table)如何在 EntityFramework 中配置这种关系(1 -> many, plus 1 -> 0 or 1, no join table)
【发布时间】:2019-01-27 17:03:17
【问题描述】:

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


商业模式:

  • 每个 Foo 都与一个 Bar 相关联。
  • 每个 Bar 可以有多个 Foo。
  • 每个 Bar 也可能有一个 特殊 Foo,(尽管可能没有)

强制“一个 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,我也不知道如何配置它。

有人知道怎么做吗?

【问题讨论】:

  • 公共虚拟 ICollection 酒吧?或 Foo 集合
  • @NaDeRStar 谢谢,应该是ICollection&lt;Foo&gt; Foos
  • @NaDeRStar 现已修复
  • 注意循环引用,以防你要序列化数据
  • @MostafaELite 同意,绝对值得向任何发现此问题的未来开发者强调!

标签: c# entity-framework


【解决方案1】:

我无法完成这项工作的根本原因是上述数据库模型没有反映在上述 C# 域对象模型中。

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

所以,类模型需要是:

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);

表示改变的 p.o.v.关系:根据数据库,Bars 并没有真正属于他们的 SpecialFoo ... Foos 有一组 Bars,它们是特殊的。

【讨论】:

  • “更改位”不是必需的。在数据库术语中,记录“拥有”所有者记录正是外键所表达的。记录从不“拥有”其他记录的集合。
  • 除非你能给出一个没有它的结构的例子,否则我会说你错了。我知道这个世界,我知道它为什么起作用,我也知道为什么以前的模型不起作用。
  • 您可以将 1:n 关系建模为非双向关系。集合或引用属性就足够了。将HasOne(b =&gt; b.SpecialFoo).WithMany() 添加到Bar 的配置并删除BarsForWhichThisIsTheSpecialFoo
  • 酷 - 这是一个更有用的输入:D 我会试一试,看看它是否有效。我更希望能够从 Foo 导航到它所特有的 Bar,但我可能没有它也可以生活。
  • @GertArnold 成功!我没有意识到 WithMany() 被允许没有参数。你想添加它作为答案吗,我会接受它。
猜你喜欢
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 2012-03-16
  • 1970-01-01
相关资源
最近更新 更多