我正试图制作几个具有复合键的表(如下例)。我一直在使用代码优先的方法来实现这个目标,但是我希望这些复合键能够层叠到子表。我们的想法是,每个子实体都有和它的父实体一样的复合键,再加上一列。
| 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
并在需要公司等相关信息时,查询该信息。