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);
}