因此,我正在深入研究 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 有几个特定的属性,但与佣金没有关系。
我对缔约方表本身的输出没有任何问题,并且理解鉴别器字段是什么,但是我不理解它创建的两个外键关系:
- Commissions 各方_AgencyPartyId
- 佣金方_CarrierPartyId
我的问题是为什么我不能在后端只拥有一个从缔约方到 Commissions_PartyId 的外键关系?如果可以的话,我如何告诉 EF 以这种方式创建它?
编辑
使用 Dmitry 的建议并使用 [InverseProperty] 属性,我最终得到了以下数据库设计,这不是所需的输出:
它实际上创建了第三个字段 (PartyId1)。所以我开始查看 EF documentation on relationships再次并开始使用不同的注释。使用 [ForeignKey("PartyId")] 属性在产生了我所期望的设计后给了我一些希望:
然而,这也产生了一些意想不到的效果。尝试使用代理机构和运营商填充数据库后,我收到异常。
这是填充代码:
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 和 Carrier
且 PartyId
等于 1,显然这是不可能的。
您需要做的是在 Commission
和 Party
之间创建关系,但这意味着 Commissions
导航属性需要也将被移至Party
。但您仍然可以通过将其设置为 protected 并仅在 Agency
和 Carrier
上公开它来将其隐藏在 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/