[英]Remove composite primary key for the join table created by entity framework
我有兩個類,產品和發票,它們之間存在多對多關系
實體框架為我創建了三個表,Products、Invoices 和一個名為 InvoiceProducts(或類似的東西)的連接表
據我所知,默認情況下,實體框架在連接表中的字段InvoiceId
和ProductId
上創建一個復合主鍵,因此這些外鍵一起必須是唯一的。
好吧,這是一個問題,因為有時一個人想在同一個調用中訂購兩個相同的項目。
我看到了這個答案,但它只有在您也在 C# 中創建連接表時才有幫助。 但是當使用實體框架時,我不再創建一個連接表,我只是創建我的類如下:
public class Invoice
{
public int Id { get; set; }
public string InvoiceNumber { get; set; }
public double TotalPrice { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public List<Invoice> Invoices { get; set; }
}
public class DB : DbContext
{
public DB() : base("MyConnectionstringName") { }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<Product> Products { get; set; }
}
那么,有什么想法嗎?
這是多對多表的默認、方便的映射,您只想將兩個表相互關聯。 類似於您所描述的內容可能涉及向 InvoiceProducts 表中添加諸如“數量”之類的內容。 (而不是復制相同的 ProductId+InvoiceId 組合)
這將涉及添加 InvoiceProduct 實體:
public class InvoiceProduct
{
[Key, ForeignKey(nameof(Invoice), Column(Order=0)]
public int InvoiceId { get; set; }
[Key, ForeignKey(nameof(Product), Column(Order=1)]
public int ProductId { get; set; }
public int Quantity { get; set; }
public virtual Invoice Invoice { get; set; }
public virtual Product Product { get; set; }
}
Invoice 和 Product 實體中的導航屬性需要分別更改為 InvoiceProducts 而不是 Products 和 Invoices。 您仍然可以從那里訪問相應的集合,但不太方便,因為集合將被鍵入 InvoiceProduct,這樣您就可以訪問關系的 Quantity 列。 例如,要列出發票的產品,您需要使用invoice.InvoiceProducts.Select(x => x.Product);
而不是invoice.Products
。
默認的多對多映射更方便,但僅限於表示關系。 映射連接表實體可以讓您更靈活地滿足此類要求。
編輯:另一種方法是使用連接表將多對多替換為一對多對一關系,該連接表具有每個表的 FK 的專用 PK 列。
例如:
public class InvoiceProduct
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceProductId { get; set; }
[ForeignKey(nameof(Invoice), Column(Order=0)]
public int InvoiceId { get; set; }
[ForeignKey(nameof(Product), Column(Order=1)]
public int ProductId { get; set; }
public virtual Invoice Invoice { get; set; }
public virtual Product Product { get; set; }
}
就個人而言,我更喜歡 Quantity 列中組合 forms 的 PK。 使用這種方法查看數據確實看起來像一個錯誤。 當您查看諸如列出產品的發票之類的東西時,這些通常顯示為產品、價格、數量和總計。 如果我訂購同一產品的 10 個實例,我希望看到該產品的數量為 10,並且同一產品的訂單項總數為 10 個。 使用 Quantity 字段的數據架構或 EF 實現在架構上沒有任何錯誤。 如果您想在刪除產品發票關聯時使用類似軟刪除關聯的方法,則需要相同的方法。 (即一個 IsActive 而不是刪除連接行)這將需要以相同的方式定義一個帶有 IsActive 標志的 InvoiceProduct 實體。 (對於跟蹤諸如 CreatedBy/Date、ModifiedBy/Date 等內容也是如此)
添加數量列在我看來在架構上是錯誤的,對你來說不是嗎?
不,但它是你的數據 model。如果你想要它,那么 model 就像
public class InvoiceLine
{
public int InvoiceId { get; set; }
public int InvoiceLineId { get; set; }
public int ProductId{ get; set; }
public virtual Invoice Invoice { get; set; }
public virtual Product Product { get; set; }
}
配置如下:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>()
.HasMany(i => i.Products)
.WithMany(p => p.Invoices)
.UsingEntity<InvoiceLine>(
e => e.HasOne( il => il.Product)
.WithMany()
.HasForeignKey(il => il.ProductId),
e => e.HasOne(il => il.Invoice)
.WithMany()
.HasForeignKey(il => il.InvoiceId),
e => e.HasKey(e => new { e.InvoiceId, e.InvoiceLineId })
);
base.OnModelCreating(modelBuilder);
}
請注意您如何仍然擁有多對多並且不必直接處理 InvoiceLine 實體。 它像這樣創建表格
CREATE TABLE [InvoiceLine] (
[InvoiceId] int NOT NULL,
[InvoiceLineId] int NOT NULL,
[ProductId] int NOT NULL,
CONSTRAINT [PK_InvoiceLine] PRIMARY KEY ([InvoiceId], [InvoiceLineId]),
CONSTRAINT [FK_InvoiceLine_Invoice_InvoiceId] FOREIGN KEY ([InvoiceId]) REFERENCES [Invoice] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_InvoiceLine_Product_ProductId] FOREIGN KEY ([ProductId]) REFERENCES [Product] ([Id]) ON DELETE CASCADE
);
CREATE INDEX [IX_InvoiceLine_ProductId] ON [InvoiceLine] ([ProductId]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.