C# 使用多对多关系时,实体框架不会更新

C# 使用多对多关系时,实体框架不会更新,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我使用了从Class1到Class2的多对多关系。正是这样: public class Class1{ [Key] public int Id { get; set; } public virtual IList<Class2> Classes2 { get; set; } //... } public class Class2{ [Key] public int Id { get; set; } //... no na

我使用了从
Class1
Class2
的多对多关系。正是这样:

public class Class1{
    [Key]
    public int Id { get; set; }

    public virtual IList<Class2> Classes2 { get; set; }

    //...
}

public class Class2{
    [Key]
    public int Id { get; set; }

    //... no navigational parameter
    // there is no need for navigational when using fluent API below.
    // However the navigational presence does not affects the issue
}
但是,
SaveChanges
不会更新多对多数据

如何正确更新新绑定的多对多参数


我只想删除或添加关系,我不想添加或删除Classes2记录。

由于对所问问题的误解,我已替换了我在此处给出的原始答案

后来事情澄清了,我意识到原来的答案与这个问题无关

因此,下面是我对EF的多对多映射的看法,以及更新涉及的关系

我在实体的名称中使用了“EF”(
TeacherEFs
StudentEFs
,以及
teacherefssstudentefs
),实体框架的多对多映射将使用它们

其他(
教师
学生
教师学生
)用于控制所有表格数据的常规CRUD操作

尽管您可以使用fluent API,但数据注释足以设置此设置,下面显示了两种方法的示例实体:

// Manual method - you control the relationship table
public class Teacher
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeachersStudents> TeachersStudents { get; set; }
}

public class Student
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeachersStudents> TeachersStudents { get; set; }
}

public class TeachersStudents
{
    [Key]
    public int Id { get; set; }
    [Index("IX_Teacher_Student", 1)]
    public int TeacherId { get; set; }
    [Index("IX_Teacher_Student", 2)]
    public int StudentId { get; set; }
    [ForeignKey("TeacherId")]
    public virtual Teacher Teacher { get; set; }
    [ForeignKey("StudentId")]
    public virtual Student Student { get; set; }
}

// Automatic method - Entity Framework controls the relationship table
public class TeacherEF
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<StudentEF> StudentEFs { get; set; }
}

public class StudentEF
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeacherEF> TeacherEFs { get; set; }
}
请注意,Entity Framework使用我们在类中提供的关系向数据库添加了第三个表:

public virtual ICollection<TeacherEF> TeachersEF { get; set; }
public virtual ICollection<StudentEF> StudentsEF { get; set; }

我已经替换了我在这里给出的原始答案,因为对所问问题的误解

后来事情澄清了,我意识到原来的答案与这个问题无关

因此,下面是我对EF的多对多映射的看法,以及更新涉及的关系

我在实体的名称中使用了“EF”(
TeacherEFs
StudentEFs
,以及
teacherefssstudentefs
),实体框架的多对多映射将使用它们

其他(
教师
学生
教师学生
)用于控制所有表格数据的常规CRUD操作

尽管您可以使用fluent API,但数据注释足以设置此设置,下面显示了两种方法的示例实体:

// Manual method - you control the relationship table
public class Teacher
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeachersStudents> TeachersStudents { get; set; }
}

public class Student
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeachersStudents> TeachersStudents { get; set; }
}

public class TeachersStudents
{
    [Key]
    public int Id { get; set; }
    [Index("IX_Teacher_Student", 1)]
    public int TeacherId { get; set; }
    [Index("IX_Teacher_Student", 2)]
    public int StudentId { get; set; }
    [ForeignKey("TeacherId")]
    public virtual Teacher Teacher { get; set; }
    [ForeignKey("StudentId")]
    public virtual Student Student { get; set; }
}

// Automatic method - Entity Framework controls the relationship table
public class TeacherEF
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<StudentEF> StudentEFs { get; set; }
}

public class StudentEF
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual IList<TeacherEF> TeacherEFs { get; set; }
}
请注意,Entity Framework使用我们在类中提供的关系向数据库添加了第三个表:

public virtual ICollection<TeacherEF> TeachersEF { get; set; }
public virtual ICollection<StudentEF> StudentsEF { get; set; }

好吧,多对多关系要求两个类都持有导航属性,而一对多只需要在成为关系中的“一”的类上。无论如何
virtual IList Classes2{get;set;}
试图更改它
public virtual..
?使用Fluent API时不需要导航参数。但是,导航属性不影响此问题。我忘了在问题中写“public”。已经编辑过。afaik,多对多关系要求两个类都持有navgational属性,而一对多只需要在成为关系中“一”的类上使用。无论如何
virtual IList Classes2{get;set;}
试图更改它
public virtual..
?使用Fluent API时不需要导航参数。但是,导航属性不影响此问题。我忘了在问题中写“public”。已编辑。如果我将一个child2实例的状态设置为“已删除”。它会从数据库中删除Child2还是仅仅删除关系?我只想删除关系。我猜将状态设置为delete会将其从数据库中删除如果您从对象中删除了关系,它将不会在数据库中更新-只有当EF被告知存储中存在一个对象并且需要更新时,它才会影响它。但是,如果说从父项集合中删除该项,而不是从数据库中删除该项,则意味着下次从数据库中加载父项时,以前“删除”的子项将再次加载……我以前也遇到过同样的问题,我用同样的方法解决了这个问题。然而,我认为这是一个可怕的方法应用于开发。“我急切地等待一个新的、更好的、可行的解决方案。”史蒂夫帕德莫尔。我是说,如果我设置了
db.Entry(child.State=EntityState.Deleted
,它将从数据库中删除。不仅仅是关系。是的,它将在SaveChanges()时从数据库中删除。如果我将一个child2实例的状态设置为deleted。它会从数据库中删除Child2还是仅仅删除关系?我只想删除关系。我猜将状态设置为delete会将其从数据库中删除如果您从对象中删除了关系,它将不会在数据库中更新-只有当EF被告知存储中存在一个对象并且需要更新时,它才会影响它。但是,如果说从父项集合中删除该项,而不是从数据库中删除该项,则意味着下次从数据库中加载父项时,以前“删除”的子项将再次加载……我以前也遇到过同样的问题,我用同样的方法解决了这个问题。然而,我认为这是一个可怕的方法应用于开发。“我急切地等待一个新的、更好的、可行的解决方案。”史蒂夫帕德莫尔。我是说,如果我设置了
db.Entry(child.State=EntityState.Deleted
,它将从数据库中删除。不仅仅是关系。是的,它将在保存更改()时从数据库中删除。
public virtual ICollection<TeacherEF> TeachersEF { get; set; }
public virtual ICollection<StudentEF> StudentsEF { get; set; }
public ActionResult Edit(TeacherEF teacherEF)
        {
            if (ModelState.IsValid)
            {
                using (var context = new MyContext())
                {
                    TeacherEF existingTeacherEF = context.TeacherEFs.Include("StudentEFs").FirstOrDefault(t => t.Id == teacherEF.Id);

                    if (teacherEF.StudentEFs == null)
                    {
                        teacherEF.StudentEFs = new List<StudentEF>();
                    }

                    // Add new StudentEfs to the existingTeacherEF
                    List<StudentEF> studentEfsToAdd = new List<StudentEF>();

                    foreach (StudentEF studentEf in teacherEF.StudentEFs)
                    {
                        // Use a loop/where clause/extension method  etc. on the passed in teacherEF's StudentEFs to see if they are already related in the existingTeacherEF.
                        // If not, add them to the list of studentEFsToAdd.
                        if (existingTeacherEF != null)
                        {
                            bool match = false;
                            foreach (StudentEF studentLookup in existingTeacherEF.StudentEFs)
                            {
                                if (studentLookup.Id == studentEf.Id)
                                {
                                    match = true;
                                    break;
                                }
                            }
                            if (!match)
                            {
                                // If we do not have a match (the existingTeacher's StudentEFs do not contain the one we are currently looking at ('student')...)
                                // Let's add this 'student' to studentEfsToAdd.
                                studentEfsToAdd.Add(studentEf);
                            }
                            else
                            {
                                // No need for action - already related
                            }
                        }
                    }

                    // Delete non-existant StudentEfs from the existingTeacherEF
                    List<StudentEF> studentEfsToDelete = new List<StudentEF>();

                    if (existingTeacherEF != null)
                    {
                        foreach (StudentEF studentEf in existingTeacherEF.StudentEFs)
                        {
                            bool match = false;
                            // Use a loop/where clause/extension method  etc. on the passed in teacherEF's StudentEFs to see if they are already related in the existingTeacherEF.
                            // If not, add them to the list of studentEFsToAdd.
                            foreach (StudentEF studentLookup in teacherEF.StudentEFs)
                            {
                                if (studentLookup.Id == studentEf.Id)
                                {
                                    match = true;
                                    break;
                                }
                            }

                            if (!match)
                            {
                                // If we do not have a match (the teacherEF's StudentEFs contains a 'student' that is not already related with existingTeacherEF...)
                                // Let's add this 'student' to studentEfsToDelete.

                                studentEfsToDelete.Add(studentEf);
                            }
                            else
                            {
                                // No need for action - already related
                            }
                        }

                        // Update the context with the StudentEFs we have, and Add or Delete them from the existingTeacherEF before SaveChanges();
                        foreach (StudentEF studentEf in studentEfsToAdd)
                        {
                            if (context.Entry(studentEf).State == EntityState.Detached)
                            {
                                context.StudentEFs.Attach(studentEf);
                            }

                            existingTeacherEF.StudentEFs.Add(studentEf);
                        }

                        foreach (StudentEF studentEf in studentEfsToDelete)
                        {
                            if (context.Entry(studentEf).State == EntityState.Detached)
                            {
                                context.StudentEFs.Attach(studentEf);
                            }

                            existingTeacherEF.StudentEFs.Remove(studentEf);
                        }
                    }

                    context.SaveChanges();
                }
            }

            return View(teacherEF);
        }