将组合键与实体框架核心结合使用,并将其中的一部分用作外键



我正在尝试制作几个具有复合键的表(下面的示例(。我已经能够使用代码优先方法实现这一点,但我希望这些组合键可以级联到子表。这个想法是,每个子实体将具有与其父实体相同的组合键以及多一列。

| 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 属性(通过HasForeignKeyfluent 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,并在需要这些信息时查找相关信息,例如公司。

最新更新