c# - EF核心: how to share foreign key properties between several zero/one-to-many relationships

标签 c# entity-framework inheritance entity-framework-core

因此,我正在深入研究 EF Core 并尝试继承和 TPH 模式(我之前没有这方面的经验)。 EF 创建的结果数据库不是我所期望的,我想知道是否有可能使用 Fluent-api 获得我正在寻找的结果,或者我是否完全没有捕获重点。

首先,这是我的 POCO 类(class):

public class Commission
{
    public int Id { get; set; }
    public string Description { get; set; }
    public double Rate { get; set; }
}

public class Party
{
    public int PartyId { get; set; }
    public string Name { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

public class Agency : Party
{
    public string AgencyCode { get; set; }
    public ICollection<Commission> Commissions { get; set; }
}

public class Carrier : Party
{
    public string CarrierCode { get; set; }
    public ICollection<Commission> Commissions { get; set; }
}

public class Principal : Party
{
    public string Website { get; set; }
    public string DistrictCode { get; set; }
}

还有我的上下文类,以防万一:

public class PartyContext : DbContext
{
    public DbSet<Agency> Agencies { get; set; }
    public DbSet<Carrier> Carriers { get; set; }
    public DbSet<Party> Parties { get; set; }
    public DbSet<Commission> Commissions { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=LAPTOP-PC\SQLEXPRESS;Database=MyDatabase;Trusted_Connection=True;");
    }
}

基本上,Agency、Carrier 和 Primary 都继承自 Party,因此它们应该具有与 Party 相同的属性。代理机构和承运人具有其他特定属性,并且应与佣金具有零或一对多关系。此外,Principal 有几个特定的​​属性,但与佣金没有关系。

生成的数据库如下: Resulting EF Database

我对缔约方表本身的输出没有任何问题,并且理解鉴别器字段是什么,但是我不理解它创建的两个外键关系:

  • Commissions 各方_AgencyPartyId
  • 佣金方_CarrierPartyId

我的问题是为什么我不能在后端只拥有一个从缔约方到 Commissions_PartyId 的外键关系?如果可以的话,我如何告诉 EF 以这种方式创建它?

编辑

使用 Dmitry 的建议并使用 [InverseProperty] 属性,我最终得到了以下数据库设计,这不是所需的输出: Resulting Database from InverseProperty

它实际上创建了第三个字段 (PartyId1)。所以我开始查看 EF documentation on relationships再次并开始使用不同的注释。使用 [ForeignKey("PartyId")] 属性在产生了我所期望的设计后给了我一些希望:

Resulting Database from ForeignKey attribute

然而,这也产生了一些意想不到的效果。尝试使用代理机构和运营商填充数据库后,我收到异常。

这是填充代码:

PartyContext _context = new PartyContext();
        // Add an Agency
        var agencyCommission1 = new Commission
        {
            Description = "Contract",
            Rate = 0.075
        };

        var agencyCcommission2 = new Commission
        {
            Description = "Hauling",
            Rate = 0.10
        };

        var agencyCommissionList = new List<Commission>
        {
            agencyCommission1, agencyCcommission2
        };

        var agency = new Agency
        {
            Name = "Agency International",
            Address1 = "12345 Main Street",
            Address2 = "Suite 100",
            City = "Chicago",
            State = "IL",
            Zip = "31202",
            AgencyCode = "AI",
            Commissions = agencyCommissionList
        };

        // Add Carrier
        var carrierCommission1 = new Commission
        {
            Description = "Coal",
            Rate = 0.15
        };

        var carrierCommission2 = new Commission
        {
            Description = "Mining",
            Rate = 0.115
        };

        var carrierCommissionList = new List<Commission>
        {
            carrierCommission1, carrierCommission2
        };

        var carrier = new Carrier
        {
            Name = "Carrier International",
            Address1 = "54321 Main Street",
            Address2 = "Suite 300",
            City = "Cleveland",
            State = "OH",
            Zip = "44115",
            CarrierCode = "CI",
            Commissions = carrierCommissionList
        };

        _context.Agencies.Add(agency);
        _context.Carriers.Add(carrier);

        try
        {
            _context.SaveChanges();
        }
        catch(Exception ex)
        {
            return;
        }

添加代理时出现的异常是“无法将‘EFTest.Agency’类型的对象转换为‘EFTest.Carrier’类型。”尝试添加运营商时出现的异常是“无法将‘EFTest.Carrier’类型的对象转换为‘EFTest.Agency’类型。”

我要补充一点,当使用原始的 EF 设计时,程序确实按预期工作,但是附加字段和外键让我的强制症有点疯狂:) 欢迎任何更多想法!

最佳答案

如果将两个关系配置为使用与外键相同的属性,您仍然有两个关系。因此,当添加 PartyId 等于 1 EF 的 Commission 时,会将其解释为与 PartyId 相等的 Agency 相关为 1 CarrierPartyId 等于 1,显然这是不可能的。

您需要做的是在 CommissionParty 之间创建关系,但这意味着 Commissions 导航属性需要也将被移至Party。但您仍然可以通过将其设置为 protected 并仅在 AgencyCarrier 上公开它来将其隐藏在 Principal 和其他派生类上:

public class PartyContext : DbContext
{
    public PartyContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet<Agency> Agencies { get; set; }
    public DbSet<Carrier> Carriers { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Party>().HasMany(typeof(Commission), "Commissions").WithOne();
    }
}

public class Party
{
    public int PartyId { get; set; }
    protected ICollection<Commission> Commissions { get; set; }
}

public class Agency : Party
{
    public new ICollection<Commission> Commissions
    {
        get { return base.Commissions; }
        set { base.Commissions = value; }
    }
}

public class Carrier : Party
{
    public new ICollection<Commission> Commissions
    {
        get { return base.Commissions; }
        set { base.Commissions = value; }
    }
}

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

关于c# - EF核心: how to share foreign key properties between several zero/one-to-many relationships,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41168651/

相关文章:

c# - 是否可以在不允许升级到 DTC 的情况下将 .NET 的 TransactionScope 与 Sql Server 2005 一起使用?

c# - 索引越界问题

c# - 使用ListView控件显示数据但加入一个引用表

c# - DBcontext.Database.Log : executable sql query

c# - 如何从 TypeInfo 获取声明和继承的成员

java - Java 基类中的私有(private)方法的动态绑定(bind)如何工作?

c++ - 继承,为什么要为基类调用两个构造函数,C++

c# - 在 WPF 中的网格中的单元格之间拖放自定义控件

c# - WPF DataContext 不更新子级

c# - 迁移 "Legacy"SQLite 数据库以使用 Entity Framework 时的主键问题