![](/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.