首页 > 解决方案 > 将组合键与 Entity Framework Core 一起使用并将其中的一部分用作外键

问题描述

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

| 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 使用代码优先的方法来做这样的事情?

标签: c#sqlentity-frameworkef-code-firstef-core-3.1

解决方案


回答你的具体问题

反正有没有让 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对都代表一个相同的关系,因此最好只在一个地方进行,以避免配置冲突。


推荐阅读