如果 EF Core 5,则以多对多关系播种数据

Ser*_*rko 10 c# asp.net entity-framework-core

我有用户实体

public class User
{
    public int UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }

    public ICollection<Technology> Technologies { get; set; } = new List<Technology>();
}
Run Code Online (Sandbox Code Playgroud)

我有技术实体

public class Technology
{
    public int TechnologyId { get; set; }
    public string TitleTechnology { get; set; }
    public int GroupId { get; set; }
    public Group Group { get; set; }
    public ICollection<User> Users { get; set; } = new List<User>();
}
Run Code Online (Sandbox Code Playgroud)

我想创建多对多关系,所以我有这样的OnModelCreating方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var groupList = new List<Group>
    {
        new Group {GroupId = 1, TitleGroup = ".NET"}
    };

    var technologyList = new List<Technology>
    {
        new Technology {TechnologyId = 1, GroupId = 1, TitleTechnology = ".NET 5"},
        new Technology {TechnologyId = 2, GroupId = 1, TitleTechnology = ".NET Framework 4.8"},
        new Technology {TechnologyId = 3, GroupId = 1, TitleTechnology = "EF 6"},
        new Technology {TechnologyId = 4, GroupId = 1, TitleTechnology = "ASP.NET MVC 5"}
    };

    var userList = new List<User>
    {
        new User
        {
            UserId = 1, FirstName = "Serhii", LastName = "Yurko", Email = "test", Password = "test",
            Technologies = new List<Technology> {technologyList[0], technologyList[1]}
        }
    };

    modelBuilder.Entity<Technology>().HasOne(exp => exp.Group).WithMany(exp => exp.Technologies).HasForeignKey(exp => exp.GroupId);
    modelBuilder.Entity<User>().HasMany(p => p.Technologies).WithMany(p => p.Users)
        .UsingEntity(j => j.ToTable("UserTechnology"));

    modelBuilder.Entity<User>().HasData(userList);
    modelBuilder.Entity<Group>().HasData(groupList);
    modelBuilder.Entity<Technology>().HasData(technologyList);
    base.OnModelCreating(modelBuilder);
}
Run Code Online (Sandbox Code Playgroud)

当我想创建迁移时,我收到这样的异常 -

无法添加实体类型“用户”的种子实体,因为它设置了导航“技术”。要种子关系,请将实体种子添加到“TechnologyUser (Dictionary<string, object>)”并指定外键值 {'UsersUserId'}。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看涉及的属性值。

如何建立正确的关系?

Ger*_*old 15

在 EF-core 中,您无法直接播种导航属性。您必须Technologies = ...User初始化中删除该行。

令人惊讶的是,当前文档中不再提及它(曾经有过),但是可以通过HasData扩展调用来通过其自己的调用来播种连接表UsingEntity(),如下所示:

.UsingEntity(j => j
    //.ToTable("UserTechnology") <= can be omitted if you agree EF's conventions that will create "TechnologyUser"
    .HasData(new[]
        {
            new { UsersID = 1, TechnologiesID = 1 },
            new { UsersID = 1, TechnologiesID = 2 }
        }
    ));
Run Code Online (Sandbox Code Playgroud)

如您所见,隐藏的连接实体由匿名类型填充,该类型具有与表字段相同的属性名称(+类型)。这需要你知道这些外键字段的命名约定(我希望我猜对了)。

您可以通过使用联结表的相当笨重的完整初始化来将这一切掌握在自己手中,如Stack Overflow 答案中所述。这允许您强制执行自己的 FK 属性名称并在种子代码中相应地使用它们。