C# 通过实体框架代码优先的方法和多对多关系为SQL Server种子设定种子

C# 通过实体框架代码优先的方法和多对多关系为SQL Server种子设定种子,c#,asp.net,sql-server,entity-framework,ef-code-first,C#,Asp.net,Sql Server,Entity Framework,Ef Code First,我首先在ASP.NETWebAPI中使用EF6代码 假设有两个模型类 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 ICol

我首先在ASP.NETWebAPI中使用EF6代码

假设有两个模型类

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; }
}
我遇到一个运行时错误,抱怨“无法从固定大小的数组中删除项”。所以很明显,这个项目试图在把木头放进咖啡桌之前把椅子上的木头去掉。因此,我将初始化更改为使用列表,如下所示

var chair = new Furniture {
    Name = "chair",
    RawMaterials = new List<RawMaterial> { wood, paint }
};
结果仍然是一样的

所以我的问题是:我如何添加测试数据,使木头同时出现在椅子和咖啡桌上?我知道这不是通常定义的多对多关系,因为原材料不知道家具。或者我应该以另一种方式定义模型

多谢各位


编辑: 我在SQLServer对象资源管理器中检查了数据库表,原始材料的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)
);

所以基本上实体框架并没有按照我需要的方式创建数据库。这就是为什么我不能在椅子和咖啡桌上都加木头的原因。我应该如何修改实体模型?

根据您的描述,家具和原材料之间的关系在我看来是多对多,而不是一对多。一件家具可以有多种原材料,同时一种原材料可以属于多种家具

无论如何,回到您的问题,要两次显示“wood”,请将种子方法更改为:

        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();
var椅子=新家具
{
Name=“主席”,
原材料=新列表
{
新原料{
Name=“paint”,
家具类=1
},
新原料{
Name=“wood”,
家具类=1
},
}
};
var咖啡桌=新家具
{
Name=“咖啡桌”,
原材料=新列表
{
新原料{
Name=“glass”,
家具类=2
},
新原料{
Name=“wood”,
家具类=2
},
}
};
上下文。家具。AddRange(新家具[]{椅子,咖啡桌});
SaveChanges();

但是这样做,它将显示重复的名称“wood”,在材质表中具有不同的Id

我非常关注您报告的错误,以至于忘记查看映射。但一旦我这么做了,事情突然变得简单起来。正如您正确指出的,这是一个多对多的关联,但它没有像一个那样映射。以下是正确映射它的方式:

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"));
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Entity()
.HasMany(f=>f.原材料)
.有很多
.Map(m=>m.MapLeftKey(“家具ID”)
.MapRightKey(“原始材料”)
.ToTable(“家具原材料”);
}
这将创建一个连接两个实体的连接表
家具原材料


但我仍然认为,运行您的代码却没有得到异常(也没有得到我后来注意到的第二个“wood”关联),这很奇怪。我想知道它是否是.Net 4.5.2版本。

我无法使用EF 6.1.3重现几乎相同的场景。这是你的真实代码还是只是问题的模型?是的,这是一个模型。但是我在上创建了一个VS项目,如果你想复制,请看一看。谢谢我可以在.NET4.5下运行此代码。你也可以试试吗?我不想在我的开发机器上安装.NET4.5.2。我无法想象是.Net的变化导致了这一点(至少,我希望不是)。我运行了他的代码,也没有得到任何异常。我也没有得到第二个木材显示,所以我改变了他的种子方法,并保持他的模型映射。我的dotnet版本是4。5@JackyNguyen但是你的代码插入了一个副本,这是绝对不会发生的。我知道,我在回答中说过,我只是想帮助OP在他的控制台上显示两次“wood”。你的回答涵盖了他很多的关系,从那里,他可以创建一个DTO对象句柄添加/更新或使用第三方,比如AutoMapper,也许?很抱歉造成混淆。在linkedvs项目中,我使用列表而不是数组,所以您没有看到异常
CREATE TABLE [dbo].[Furnitures] (
    [ID]   INT            IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.Furnitures] PRIMARY KEY CLUSTERED ([ID] ASC)
);
        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();
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"));
}