簡體   English   中英

通過具有多對多關系的實體框架代碼優先方法為 SQL Server 播種

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM