C# 使用具有实体框架核心的复合键,并将其中的一部分用作外键

C# 使用具有实体框架核心的复合键,并将其中的一部分用作外键,c#,sql,entity-framework,ef-code-first,ef-core-3.1,C#,Sql,Entity Framework,Ef Code First,Ef Core 3.1,我试图创建几个具有复合键的表(下面的示例)。我已经能够使用代码优先的方法来实现这一点,但是我希望这些复合键能够以级联的方式下放到子表中。其思想是,每个子实体将具有与其父实体相同的复合键,再加上一列 | PurchaseOrder | | ------------- | | Company (PK) | | PONum (PK) | | PuchaseOrderLine | | ---------------- | | Company (PK/FK) | | PONum (PK/FK)

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

| PurchaseOrder |
| ------------- |
| Company (PK)  |
| PONum (PK)    |

| PuchaseOrderLine |
| ---------------- |
| Company (PK/FK)  |
| PONum (PK/FK)    |
| POLine (PK)      |
从技术上讲,PurchaseOrder表与company表做的事情类似,但这对我来说不太重要,我认为如果我能够找到POLine到PO的连接,我也会找到它

这是我迄今为止的尝试:

//我的类中继承IdentityDbContext的OnModelCreating方法
模型创建时受保护的覆盖无效(ModelBuilder)
{
基于模型创建(生成器);
builder.Entity()
.DefaultConfigure(c=>new{c.Name});
builder.Entity()
.DefaultConfigure(p=>new{p.Company,p.PONum})
.HasMany(e=>e.PurchaseOrderLines)
.一个(e=>e.采购订单);
builder.Entity()
.DefaultConfigure(p=>new{p.Company,p.PONum,p.LineNum})
.HasOne(e=>e.PurchaseOrder)
.有许多(e=>e.PurchaseOrderLines);
}
//我的DefaultConfigure扩展方法
公共静态EntityTypeBuilder DefaultConfigure(此EntityTypeBuilder生成器,表达式键Expression)
其中T:可审计实体
{
//将表重命名为类型名称
builder.ToTable(typeof(T.Name.ToLower());
//配置它们传入的密钥
builder.HasKey(keyExpression);
//配置默认备用密钥
hasaAlternateKey(i=>new{i.RowId});
//归还建筑商
返回生成器;
}
当我运行此迁移并更新数据库时,我的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使用代码优先的方法来做类似的事情?

不要这样做。使用自动递增的主键。在父表中查找所需的值

复合主键只会使外键变得麻烦。如果广泛用作外键,它们的效率也较低,通常会占用更多空间


因此,
PurchaseOrder
应该有一个
PurchaseOrderId
。然后,
PurchaseOrderLine
应参考
PurchaseOrderId
,并在需要该信息时查找相关信息,如公司。

回答您的具体问题

是否有必要让efcore使用代码优先的方法来做类似的事情

当然有。显然,这两种方法不起作用,因此必须显式地配置FK属性(通过
HasForeignKey
fluent API)

e、 g.要么

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()
.DefaultConfigure(p=>new{p.Company,p.PONum,p.LineNum})
.HasOne(e=>e.PurchaseOrder)
.WithMany(e=>e.PurchaseOrderLines)
.HasForeignKey(e=>{e.Company,e.PONum});//新{p.公司,p.PONum})
.HasMany(e=>e.PurchaseOrderLines)
.WithOne(e=>e.PurchaseOrder)

.HasForeignKey(e=>{e.Company,e.PONum});//我知道如何使用自动递增的主键,但对于这个应用程序,它们不会到期。出于法律原因,这些信息可能存放在单独的数据库中,并在以后进行合并以进行审计。这样做,每个地点都有不同的公司,我仍然可以保持事物的独特性,我还使用和备用键来提高独特性的可靠性。我知道这不是最有效的路线,但这是它需要建立的方式。这是完美的,它正在做我想要它做的事情。我完全按照您在第一个示例中所做的做了,然后在我的PurchaseOrder实体生成器上只执行了.DefaultConfigure()方法,它按照我期望的方式构建了表。非常感谢你。
builder.Entity<PurchaseOrder>()
    .DefaultConfigure(p => new { p.Company, p.PONum })
    .HasMany(e => e.PurchaseOrderLines)
    .WithOne(e => e.PurchaseOrder)
    .HasForeignKey(e => { e.Company, e.PONum }); // <--