C# EF Core,如何更新与同一实体具有一对多和多对多关系的表中的记录 公共班级学生 { 公共int Id{get;set;} 公共字符串名称{get;set;} public int MainCourseId{get;set;} 公共课程主课{get;set;} 公共IList学生课程{get;set;} } 公共课 { 公共int Id{get;set;} 公共字符串CourseName{get;set;} 公共字符串说明{get;set;} } 公共课学生课程 { 公共int StudentId{get;set;} 公立学生学生{get;set;} public int CourseId{get;set;} 公共课程{get;set;} }

C# EF Core,如何更新与同一实体具有一对多和多对多关系的表中的记录 公共班级学生 { 公共int Id{get;set;} 公共字符串名称{get;set;} public int MainCourseId{get;set;} 公共课程主课{get;set;} 公共IList学生课程{get;set;} } 公共课 { 公共int Id{get;set;} 公共字符串CourseName{get;set;} 公共字符串说明{get;set;} } 公共课学生课程 { 公共int StudentId{get;set;} 公立学生学生{get;set;} public int CourseId{get;set;} 公共课程{get;set;} },c#,entity-framework,.net-core,entity-framework-core,ef-core-5.0,C#,Entity Framework,.net Core,Entity Framework Core,Ef Core 5.0,有两个问题。 第一个问题是,上面的迁移没有创建MainCourseId,因此出现了此错误。 在表“Students”上引入外键约束“FK_Students_Courses_MainCourseId”可能会导致循环或多个级联路径。请在“删除无操作”或“更新无操作”上指定,或修改其他外键约束。 无法创建约束或索引。请参阅以前的错误。“ 其次,在另一个实体结构相同的系统中,使用MainCourseId中修改的值更新现有记录不起作用。您的数据库结构有一个bug。您还需要将StudentCourse列表添

有两个问题。 第一个问题是,上面的迁移没有创建MainCourseId,因此出现了此错误。 在表“Students”上引入外键约束“FK_Students_Courses_MainCourseId”可能会导致循环或多个级联路径。请在“删除无操作”或“更新无操作”上指定,或修改其他外键约束。 无法创建约束或索引。请参阅以前的错误。“


其次,在另一个实体结构相同的系统中,使用MainCourseId中修改的值更新现有记录不起作用。

您的数据库结构有一个bug。您还需要将StudentCourse列表添加到课程类中。我觉得这不是我见过的最好的数据库结构。更好的方法是将Id添加到StudentCourse表中,如果它是主课,则添加一个标志

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MainCourseId { get; set; }
    public Course MainCourse { get; set; }
    public IList<StudentCourse> StudentCourses { get; set; }
}

public class Course
{
    public int Id { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }
}

public class StudentCourse
{
    public int StudentId { get; set; }
    public Student Student { get; set; }
    public int CourseId { get; set; }
    public Course Course { get; set; }
}
由于您使用的是net5,因此可以向类中添加其他列表

public class StudentCourse
{
    public int Id { get; set; }
    public int StudentId { get; set; }
    public Student Student { get; set; }
    public int CourseId { get; set; }
    public Course Course { get; set; }
    public bool IsMainCourse {get; set;}
}
公共班级学生
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟列表课程{get;set;}
公共虚拟列表学生课程{get;set;}
}
公共课
{
公共int Id{get;set;}
公共字符串CourseName{get;set;}
公共字符串说明{get;set;}
公共虚拟列表学生{get;set;}
公共虚拟列表学生课程{get;set;}
}

您需要进行新的init迁移以使用此结构

您的数据库结构有一个bug。您还需要将StudentCourse列表添加到课程类中。我觉得这不是我见过的最好的数据库结构。更好的方法是将Id添加到StudentCourse表中,如果它是主课,则添加一个标志

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MainCourseId { get; set; }
    public Course MainCourse { get; set; }
    public IList<StudentCourse> StudentCourses { get; set; }
}

public class Course
{
    public int Id { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }
}

public class StudentCourse
{
    public int StudentId { get; set; }
    public Student Student { get; set; }
    public int CourseId { get; set; }
    public Course Course { get; set; }
}
由于您使用的是net5,因此可以向类中添加其他列表

public class StudentCourse
{
    public int Id { get; set; }
    public int StudentId { get; set; }
    public Student Student { get; set; }
    public int CourseId { get; set; }
    public Course Course { get; set; }
    public bool IsMainCourse {get; set;}
}
公共班级学生
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟列表课程{get;set;}
公共虚拟列表学生课程{get;set;}
}
公共课
{
公共int Id{get;set;}
公共字符串CourseName{get;set;}
公共字符串说明{get;set;}
公共虚拟列表学生{get;set;}
公共虚拟列表学生课程{get;set;}
}

您需要进行新的初始化迁移以使用此结构

您不能使用创建多个级联路径的级联删除。在这里,删除一门课程将同时删除该课程的所有学生课程和将其作为主课的所有学生课程

但如果主课程是可选的,EF不会配置CascadeDelete,因为它可能应该允许您存储没有主课程的学生。因此,要解决这两个问题,只需将Student.MainCourseId的类型更改为
int?
,使其成为可选的:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual List<Course> Courses { get; set; }
    public virtual List<StudentCourse> StudentCourses { get; set; }
}

public class Course
{
    public int Id { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }
    public virtual List<Student> Students{ get; set; }
    public virtual List<StudentCourse> StudentCourses { get; set; }
}
公共班级学生
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共int?MainCourseId{get;set;}
公共课程主课{get;set;}
公共IList学生课程{get;set;}
}
或者,您可以根据需要保留它,并将关系配置为不级联删除

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? MainCourseId { get; set; }
    public Course MainCourse { get; set; }
    public IList<StudentCourse> StudentCourses { get; set; }
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.HasOne(s=>s.MainCourse)
.有很多
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity()
.HasKey(e=>new{e.StudentId,e.CourseId});
基于模型创建(modelBuilder);
}
我认为使用“跳过导航属性”可能更方便,这样学生就有课程,而课程也有学生,这可以在EF Core 5+中通过多对多映射实现,如下所示:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Student>()
                .HasOne(s => s.MainCourse)
                .WithMany()
                .OnDelete(DeleteBehavior.Restrict);

    modelBuilder.Entity<StudentCourse>()
                .HasKey(e => new { e.StudentId, e.CourseId });

    base.OnModelCreating(modelBuilder);
}
使用Microsoft.EntityFrameworkCore;
使用System.Linq;
使用制度;
使用System.Collections.Generic;
命名空间EfCore6Test
{ 
公立班学生
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共int?MainCourseId{get;set;}
公共课程主课{get;set;}
公共ICollection课程{get;}=new HashSet();
}
公共课
{
公共int Id{get;set;}
公共字符串CourseName{get;set;}
公共字符串说明{get;set;}
公共ICollection学生{get;}=new HashSet();
}
公共课学生课程
{
公共int StudentId{get;set;}
公立学生学生{get;set;}
public int CourseId{get;set;}
公共课程{get;set;}
}
公共类Db:DbContext
{
公共数据库集学生{get;set;}
公共数据库集课程{get;set;}
公共数据库集学生课程{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().HasOne(s=>s.MainCourse).WithMany().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity()有许多(s=>s.Courses)。有许多(c=>c.Students)。UsingEntity(
sc=>sc.HasOne(e=>e.Course).WithMany(),
sc=>sc.HasOne(e=>e.Student).WithMany()
); 
基于模型创建(modelBuilder);
}
配置时受保护的覆盖无效(DBContextOptions Builder Options Builder)
{
optionsBuilder.UseSqlServer(“服务器=本地主机;数据库=efCore6Test;集成安全性=true;信任服务器CE