![](/img/trans.png)
[英]Entity Framework Core Code-First: Cascade delete on a many-to-many relationship
[英]Seeding SQL Server by Entity Framework code-first approach with many-to-many relationship
我首先將 EF6 代碼與 ASP.NET Web API 一起使用。
假設有兩個模型類
public class RawMaterial {
public int ID { get; set; }
public string Name { get; set; }
}
public class Furniture {
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<RawMaterial> RawMaterials { get; set; }
}
數據庫上下文
public class FurnitureContext : DbContext {
public DbSet<RawMaterial> RawMaterials { get; set; }
public DbSet<Furniture> Furnitures { get; set; }
}
在初始化類中,
protected override void Seed (FurnitureContext context) {
var glass = new RawMaterial { Name = "glass" };
var wood = new RawMaterial { Name = "wood" };
var paint = new RawMaterial { Name = "paint" };
context.RawMaterials.AddRange(new RawMaterial[] { glass, wood, paint });
var chair = new Furniture {
Name = "chair",
RawMaterials = new RawMaterial[] { wood, paint }
};
var coffeeTable = new Furniture {
Name = "coffee table",
RawMaterials = new RawMaterial[] { wood, glass }
};
context.Furnitures.AddRange(new Furnitures[] { chair, coffeeTable });
context.SaveChanges();
}
我遇到了一個運行時錯誤,抱怨“無法從固定大小的數組中刪除項目”。 很明顯,程序試圖在將木頭添加到咖啡桌之前從椅子上移除木頭。 所以我將初始化更改為使用列表,如
var chair = new Furniture {
Name = "chair",
RawMaterials = new List<RawMaterial> { wood, paint }
};
在那之后,我可以清楚地看到木頭確實從其中一件家具的原材料中移除了。
我還嘗試從上下文中選擇木材
var chair = new Furniture {
Name = "chair",
RawMaterials = new RawMaterial[] {
context.RawMaterials.Where(r => r.Name == wood.Name).FirstOrDefault()
}
};
結果還是一樣。
所以我的問題是:如何添加測試數據,使得椅子和咖啡桌中都存在木材? 我知道這通常不是定義的多對多關系,因為 RawMaterial 不知道家具。 或者我應該以另一種方式定義模型?
謝謝你。
編輯:我檢查了 SQL Server 對象資源管理器中的數據庫表,RawMaterial 的 SQL 是
CREATE TABLE [dbo].[RawMaterials] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
[Furniture_ID] INT NULL,
CONSTRAINT [PK_dbo.RawMaterials] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_dbo.RawMaterials_dbo.Furnitures_Furniture_ID] FOREIGN KEY ([Furniture_ID]) REFERENCES [dbo].[Furnitures] ([ID])
);
GO
CREATE NONCLUSTERED INDEX [IX_Furniture_ID]
ON [dbo].[RawMaterials]([Furniture_ID] ASC);
家具的 SQL 是
CREATE TABLE [dbo].[Furnitures] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Furnitures] PRIMARY KEY CLUSTERED ([ID] ASC)
);
所以基本上實體框架沒有按照我需要的方式創建數據庫。 這就是為什么我不能在椅子和咖啡桌上都添加木頭的原因。 我應該如何修改實體模型?
我太專注於您報告的錯誤,以至於忘記查看映射。 但是一旦我這樣做了,它突然看起來很簡單。 正如您正確指出的那樣,這是一個多對多關聯,但它不像一個映射。 這是您正確映射它的方式:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Furniture>()
.HasMany(f => f.RawMaterials)
.WithMany()
.Map(m => m.MapLeftKey("FurnitureId")
.MapRightKey("RawMaterialId")
.ToTable("FurnitureRawMaterial"));
}
這將創建連接兩個實體的連接表FurnitureRawMaterial
。
我仍然認為我可以在沒有異常的情況下運行您的代碼(並且沒有得到我后來注意到的第二個“木”關聯),這很奇怪。 我想知道這是否是 .Net 4.5.2 問題。
根據您的描述,Furniture 和 RawMaterial 之間的關系在我看來是多對多而不是一對多。 一件家具可以有多種原材料,同時一種原材料可以屬於多種家具。
無論如何,回到您的問題,要顯示“木頭”兩次,請將您的 Seed 方法更改為:
var chair = new Furniture
{
Name = "chair",
RawMaterials = new List<RawMaterial>
{
new RawMaterial {
Name = "paint",
FurnitureId = 1
},
new RawMaterial {
Name = "wood",
FurnitureId = 1
},
}
};
var coffeeTable = new Furniture
{
Name = "coffee table",
RawMaterials = new List<RawMaterial>
{
new RawMaterial {
Name = "glass",
FurnitureId = 2
},
new RawMaterial {
Name = "wood",
FurnitureId = 2
},
}
};
context.Furnitures.AddRange(new Furniture[] { chair, coffeeTable });
context.SaveChanges();
但是這樣做,它會顯示重復的名稱“wood”,在您的 MAterial 表中具有不同的 Id
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.