Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果EF Core 5,则以多对多关系播种数据_C#_Asp.net_Entity Framework Core - Fatal编程技术网

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

C# 如果EF Core 5,则以多对多关系播种数据,c#,asp.net,entity-framework-core,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

我有一个用户实体

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>();
}
当我想要创建迁移时,我会收到这样一个异常-

无法添加实体类型“User”的种子实体,因为该实体具有 导航“技术”集。要种子关系,请添加 “技术用户词典”的实体种子和 指定外键值{'UsersUserId'}。考虑使用 “DbContextOptions Builder.EnableSensivedAtalogging”以查看 涉及的属性值


如何创建正确的关系?

为类添加一些属性

public class User
    {
        [Key]
        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; } 
         public ICollection<UserTechnology> UserTechnologies { get; set; } 
    }

 public class Technology
    {
        [Key]
        public int TechnologyId { get; set; }
        public string TitleTechnology { get; set; }
        public int GroupId { get; set; }
        [ForeignKey(nameof(GroupId))]
        [InverseProperty("Technologies")]
        public Group Group { get; set; }
        public ICollection<User> Users { get; set; }
        public ICollection<UserTechnology> UserTechnologies { get; set; } 
    }

public class UserTechnology
{
    
    public int UserId{ get; set; }
    public User User { get; set; }

    public int Technology TechnologyId{ get; set; }
    public Technology Technology{ get; set; }
}
        public  partial class Group()
      {        
        [Key]
        public int Id { get; set; }
        ......

               
        [InverseProperty(nameof(Technology.Group))]
        public virtual ICollection<Technology> Technologies{ get; set; }

  }
并向dbcontext添加一些代码

 modelBuilder.Entity<UserTechnology>()
            .HasKey(t => new { t.UserId, t.Techn});

        modelBuilder.Entity<UserTechnology>()
            .HasOne(pt => pt.User)
            .WithMany(p => p.UserTechnologies)
            .HasForeignKey(pt => pt.UserId);

        modelBuilder.Entity<UserTechnology>()
            .HasOne(pt => pt.Technology)
            .WithMany(t => t.UserTechnologies)
            .HasForeignKey(pt => pt.TechologyId);

向类添加一些属性

public class User
    {
        [Key]
        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; } 
         public ICollection<UserTechnology> UserTechnologies { get; set; } 
    }

 public class Technology
    {
        [Key]
        public int TechnologyId { get; set; }
        public string TitleTechnology { get; set; }
        public int GroupId { get; set; }
        [ForeignKey(nameof(GroupId))]
        [InverseProperty("Technologies")]
        public Group Group { get; set; }
        public ICollection<User> Users { get; set; }
        public ICollection<UserTechnology> UserTechnologies { get; set; } 
    }

public class UserTechnology
{
    
    public int UserId{ get; set; }
    public User User { get; set; }

    public int Technology TechnologyId{ get; set; }
    public Technology Technology{ get; set; }
}
        public  partial class Group()
      {        
        [Key]
        public int Id { get; set; }
        ......

               
        [InverseProperty(nameof(Technology.Group))]
        public virtual ICollection<Technology> Technologies{ get; set; }

  }
并向dbcontext添加一些代码

 modelBuilder.Entity<UserTechnology>()
            .HasKey(t => new { t.UserId, t.Techn});

        modelBuilder.Entity<UserTechnology>()
            .HasOne(pt => pt.User)
            .WithMany(p => p.UserTechnologies)
            .HasForeignKey(pt => pt.UserId);

        modelBuilder.Entity<UserTechnology>()
            .HasOne(pt => pt.Technology)
            .WithMany(t => t.UserTechnologies)
            .HasForeignKey(pt => pt.TechologyId);

在EF core中,不能直接为导航属性设置种子。您必须删除行技术=。。。从用户初始化

如上所述,通过扩展UsingEntity调用,可以通过其自己的HasData调用为连接表设定种子,如下所示:

.UsingEntityj=>j .ToTableUserTechnology .HasDatanew[] { {UsersID=1,TechnologiesID=1}, {UsersID=1,TechnologiesID=2} } ; 如您所见,隐藏连接实体由一个匿名类型填充,该匿名类型具有与表字段相同的属性名+类型。这要求您了解这些外键字段的命名约定,我希望我猜对了


通过使用相当笨拙的连接表的完全初始化,您可以自己完成这一切,如和中所述。这允许您强制使用自己的FK属性名称,并在种子设定代码中相应地使用它们。

在EF core中,您不能直接为导航属性设定种子。您必须删除行技术=。。。从用户初始化

如上所述,通过扩展UsingEntity调用,可以通过其自己的HasData调用为连接表设定种子,如下所示:

.UsingEntityj=>j .ToTableUserTechnology .HasDatanew[] { {UsersID=1,TechnologiesID=1}, {UsersID=1,TechnologiesID=2} } ; 如您所见,隐藏连接实体由一个匿名类型填充,该匿名类型具有与表字段相同的属性名+类型。这要求您了解这些外键字段的命名约定,我希望我猜对了

通过使用相当笨拙的连接表的完全初始化,您可以自己完成这一切,如和中所述。这允许您强制使用自己的FK属性名称,并在种子设定代码中相应地使用它们。

模型种子数据方法有一些已知的限制。最值得注意的是,它无法通过从导航属性推断关系来插入相关数据,并且必须显式添加外键值。详情请参阅-

在您的情况下,最好使用这里描述的自定义初始化逻辑方法-不要忘记仔细阅读警告

自定义初始化逻辑方法的实现: 对于模型-

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Technology> Technologies { get; set; } = new List<Technology>();
}

public class Technology
{
    public int Id { 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>();
}

public class Group
{
    public int Id { get; set; }
    public string TitleGroup { get; set; }

    public ICollection<Technology> Technologies { get; set; } = new List<Technology>();
}
因此,每当应用程序启动时,我们都可以选择检查数据库是否需要种子设定,如-

public static void Main(string[] args)
{
    IHost host = CreateHostBuilder(args).Build();
    host.GenerateSeedDataAsync().Wait();
    host.Run();
}
模型种子数据方法有一些已知的局限性。最值得注意的是,它无法通过从导航属性推断关系来插入相关数据,并且必须显式添加外键值。详情请参阅-

在您的情况下,最好使用这里描述的自定义初始化逻辑方法-不要忘记仔细阅读警告

自定义初始化逻辑方法的实现: 对于模型-

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Technology> Technologies { get; set; } = new List<Technology>();
}

public class Technology
{
    public int Id { 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>();
}

public class Group
{
    public int Id { get; set; }
    public string TitleGroup { get; set; }

    public ICollection<Technology> Technologies { get; set; } = new List<Technology>();
}
因此,每当应用程序启动时,我们都可以选择检查数据库是否需要种子设定,如-

public static void Main(string[] args)
{
    IHost host = CreateHostBuilder(args).Build();
    host.GenerateSeedDataAsync().Wait();
    host.Run();
}

这只是模拟多对多关联的另一种方法。“我不认为奥普要求的是另一种选择。”格塔诺尔,一开始我是按照你的方式考虑的。并将发布几乎相同的答案。但在此之后,我想知道是否添加了第三个表,也许ef不需要添加这些额外的数据。这只是一个实验,我想看看结果。@GertArnold-但你打破了它。如果第一个解决方案不起作用,我会提供另一个解决方案,但你已经发布了。这只是建模多对多关联的另一种方法。“我不认为奥普要求的是另一种选择。”格塔诺尔,一开始我是按照你的方式考虑的。并将发布几乎相同的答案。但在此之后,我想知道是否添加了第三个表,也许ef不需要添加这些额外的数据。这只是一个实验,我想看看结果。@GertArnold-但你打破了它。如果第一个解决方案不起作用,我会提供另一个解决方案,但你已经发布了。虽然我的回答简单且技术上回答了眼前的问题,但我必须说,在这种情况下,我也更喜欢定制种子。主要是因为
它看起来不仅仅是一些基本数据的简单播种。这是商业数据。我甚至会更进一步,使用指定的业务方法来创建这样的数据。例如,创建一个用户可能涉及到业务逻辑。因此,只能通过该逻辑创建用户。在数据层中不应该有任何阴暗的角落也会发生这种情况,绕过所有这些规则。这意味着:这种方法和连接可以+1,但我会在这里调用业务逻辑方法。@GertArnold谢谢。我非常感谢你的建议,我必须同意这将是一个更专业的方法。虽然我的回答简单且技术上回答了眼前的问题,但我必须说,在这种情况下,我也更喜欢定制种子。主要是因为这看起来不仅仅是一些基本数据的简单播种。这是商业数据。我甚至会更进一步,使用指定的业务方法来创建这样的数据。例如,创建一个用户可能涉及到业务逻辑。因此,只能通过该逻辑创建用户。在数据层中不应该有任何阴暗的角落也会发生这种情况,绕过所有这些规则。这意味着:这种方法和连接可以+1,但我会在这里调用业务逻辑方法。@GertArnold谢谢。我非常感谢你的建议,我必须同意这将是一种更专业的方法。
public static void Main(string[] args)
{
    IHost host = CreateHostBuilder(args).Build();
    host.GenerateSeedDataAsync().Wait();
    host.Run();
}