c# - 映射多对多关系与/外键引用

标签 c# .net sql-server entity-framework relational-database

对于精通 EF 的用户来说,这应该是一个简单的问题。

关于表之间的关系应该如何看待,我有以下模式(在我的脑海中)。

[FooBar]      [Foo]          [Bar]

FooId PK,FK   Id PK          Id PK
BarId PK,FK   BarId FK       Name
IsRead        Name           Description
              Description    

虽然,当我尝试使用 EF 代码优先生成模式时,它无法像我解释的那样解释实体之间的关系(添加外键 FooId[bar] 表)并且无法完全创建 [FooBar] 桥接表。

如果有人可以指导我如何使用 EF4 代码优先实现上述架构,我将不胜感激。解决方案是否涉及我的 POCO 模型的属性、流畅的配置或两者的混合都无关紧要 - 只要创建了所需的数据库模式即可。


POCO 模型:

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }
    public int BarId { get; set; }

    public Bar Bar { get; set; } /* bar entity */

    public virtual ICollection<Bar> BridgedBars { get; set; }

    public Foo()
    {
        Bars = new List<Bar>();
    }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<Foo> BridgedFoos { get; set; }

    public Bar()
    {
        Foos = new List<Foo>();
        BridgedFoos = new List<Foo>();
    }
}

public class FooBar
{
    public int FooId { get; set; }
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}

最佳答案

您的模型确实会创建一个外键 FooIdBar属于 Foo.BrideBars 定义的关系. EF 不会将此导航属性与 ICollection<Foo> 之一相关联Bar 中的属性因为它们有两个,EF 无法唯一确定哪对是正确的。结果,它为 Foo.BrideBars 创建了关系另一端没有导航属性。可以说,有一个看不见的Bar.Foo导致外键的属性。

您要映射到模型的数据库模式并不真正表示多对多关系,而是与中间“桥”实体的两个一对多关系 FooBar .您必须在导航属性中使用此类来定义正确的关系。它看起来像这样:

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public int BarId { get; set; }
    public Bar Bar { get; set; }

    public virtual ICollection<FooBar> FooBars { get; set; }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<FooBar> FooBars { get; set; }

}

public class FooBar
{
    [Key, Column(Order = 0)]
    public int FooId { get; set; }
    [Key, Column(Order = 1)]
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}

正确的关系将通过此模型中的命名约定来检测。仅适用于 FooBar entity 有必要显式定义一个键,因为属性名称不符合约定(没有 Id 和没有 FooBarId 属性)。在此模型中,在 FooBar 中使用复合键是有意义的.

我想,您的真实类和属性没有名称 FooBar .如果您的真实姓名不遵循约定,您可能必须使用注释或使用 Fluent API 来指定关系:

modelBuilder.Entity<Foo>()
    .HasRequired(f => f.Bar)
    .WithMany(b => b.Foos)
    .HasForeignKey(f => f.BarId);

modelBuilder.Entity<FooBar>()
    .HasKey(fb => new { fb.FooId, fb.BarId }); // replaces the [Key] annotations

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Foo)
    .WithMany(f => f.FooBars)
    .HasForeignKey(fb => fb.FooId);

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Bar)
    .WithMany(b => b.FooBars)
    .HasForeignKey(fb => fb.BarId);

在你的数据库模式中 FooBar表将有一个复合主键:

[FooBar]       [Foo]          [Bar]

FooId PK,FK    Id PK          Id PK
BarId PK,FK    BarId FK       Name
IsRead         Name           Description
               Description    

但在FooBar中有PK是必需的,因为 EF 模型中的每个实体都必须定义一个键属性(单个或组合),它映射到数据库表中的主键。

在这个问题中 - Create code first, many to many, with additional fields in association table - 有关如何处理此类关系的更多详细信息。 (有时人们也称它为“多对多关系与有效载荷”(IsRead 属性是示例模型中的“有效载荷”),但实际上它不是多对多.)

关于c# - 映射多对多关系与/外键引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10866706/

相关文章:

c# - docker/linux aspnet core 2.03 截断发布数据。这怎么可能?

c# - AsyncTaskMethodBuilder AwaitUnsafeOnCompleted 与等待时的 AwaitOnCompleted

c# - 识别内存泄漏

.net - 你如何处理 .NET 中生成的 JSON 中的 Infinity

c# - 使用sdf数据库(SQL Server Compact 3.5数据库文件)无需安装Microsoft sql server C#

c# - 使用有序的 List<Article> ,我想获取下一个/上一个 url

C# 无法从 Excel 电子表格导入所有单元格

c# - WPF 在 Tab 键上禁用窗口关闭和最小化按钮

SQL Server 选择两个值之间的行

sql-server - SQL Server 无法从 XML 字符串解析 CDATA