我正在尝试制作几个具有复合键的表(下面的示例(。我已经能够使用代码优先方法实现这一点,但我希望这些组合键可以级联到子表。这个想法是,每个子实体将具有与其父实体相同的组合键以及多一列。
| PurchaseOrder |
| ------------- |
| Company (PK) |
| PONum (PK) |
| PuchaseOrderLine |
| ---------------- |
| Company (PK/FK) |
| PONum (PK/FK) |
| POLine (PK) |
从技术上讲,PurchaseOrder 表会做与公司表类似的事情,但这对我来说稍微不那么重要,我认为如果我能够弄清楚 POLine 到 PO 的连接,我也会弄清楚那个。
这是我到目前为止的尝试:
// OnModelCreating method in my class that inherits IdentityDbContext<IdentityUser>
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Company>()
.DefaultConfigure(c => new { c.Name });
builder.Entity<PurchaseOrder>()
.DefaultConfigure(p => new { p.Company, p.PONum })
.HasMany(e => e.PurchaseOrderLines)
.WithOne(e => e.PurchaseOrder);
builder.Entity<PurchaseOrderLine>()
.DefaultConfigure(p => new { p.Company, p.PONum, p.LineNum })
.HasOne(e => e.PurchaseOrder)
.WithMany(e => e.PurchaseOrderLines);
}
// My DefaultConfigure extension method
public static EntityTypeBuilder<T> DefaultConfigure<T>(this EntityTypeBuilder<T> builder, Expression<Func<T, object>> keyExpression)
where T : AuditableEntity
{
// Rename table to the types name
builder.ToTable(typeof(T).Name.ToLower());
// Configure the keys they passed in
builder.HasKey(keyExpression);
// Configure the default alternate key
builder.HasAlternateKey(i => new { i.RowId });
// Give the builder back
return builder;
}
当我运行此迁移并更新我的数据库时,这是我的 PurchaseOrderLine 表上的内容:
| COLUMN_NAME | CONSTRAINT_NAME |
| -------------------- | -------------------------------------------------------------------------- |
| RowId | AK_PurchaseOrderLine_RowId |
| PurchaseOrderCompany | FK_PurchaseOrderLine_PurchaseOrder_PurchaseOrderCompany_PurchaseOrderPONum |
| PurchaseOrderPONum | FK_PurchaseOrderLine_PurchaseOrder_PurchaseOrderCompany_PurchaseOrderPONum |
| Company | PK_PurchaseOrderLine |
| LineNum | PK_PurchaseOrderLine |
| PONum | PK_PurchaseOrderLine |
EFCore 只是使用默认命名方案添加了两个新列,并没有使用我已经拥有的列。 无论如何可以让 efcore 使用代码优先方法做这样的事情吗?
回答您的具体问题
无论如何可以让 efcore 使用代码优先方法做这样的事情吗?
当然有。只有传统的外键名称显然不起作用,因此您必须显式配置 FK 属性(通过HasForeignKey
fluent API(。
例如,要么
builder.Entity<PurchaseOrderLine>()
.DefaultConfigure(p => new { p.Company, p.PONum, p.LineNum })
.HasOne(e => e.PurchaseOrder)
.WithMany(e => e.PurchaseOrderLines)
.HasForeignKey(e => { e.Company, e.PONum }); // <--
或
builder.Entity<PurchaseOrder>()
.DefaultConfigure(p => new { p.Company, p.PONum })
.HasMany(e => e.PurchaseOrderLines)
.WithOne(e => e.PurchaseOrder)
.HasForeignKey(e => { e.Company, e.PONum }); // <--
请注意,两个Has
/With
对都表示相同的关系,因此最好只在一个地方进行,以避免配置冲突。
不要这样做。 使用自动递增的主键。 在父表中查找所需的值。
复合主键只会使外键变得繁琐。 如果广泛用作外键,它们的效率也较低,并且通常使用更多空间。
所以,PurchaseOrder
应该有一个PurchaseOrderId
. 然后PurchaseOrderLine
应该参考PurchaseOrderId
,并在需要这些信息时查找相关信息,例如公司。