EF 4.1和“集合被修改; 枚举操作可能无法执行。“exception

在过去的两天里,这让我疯狂。 我有3个非常基本的类(好,可读性降低)

public class Employee { public string Name { set; get; } virtual public Employer Employer { set; get; } public Employee(string name) { this.Name = name; } } 

 // this basically ties Employee and his role in a company. public class EmployeeRole{ public int Id { set; get; } virtual public Employee Employee { set; get; } public string Role { set; get; } public EmployeeRole(Employee employee, string role){ this.Employee = employee; this.Role = role; } } 

 public class Employer{ public string Name { set; get; } List employees = new List(); virtual public List Employees { get { return this.employees; } } public Employer(string name, Employee creator){ this.Name = name; this.Employees.Add(new EmployeeRole(creator, "Creator")); creator.Employer = this; } } 

看起来很简单。 没有为DbContext中的那些类做任何特定配置。

但是,当我运行以下代码时

 using (DbContext db = DbContext.GetNewDbContext()){ Employee creator = new Employee("Bob"); db.Employees.Add(creator); db.SaveChanges(); Employer employer = new Employer("employer", creator); db.Employers.Add(employer); db.SaveChanges(); // I know I can call SaveChanges once (and it actually works in this case), // but I want to make sure this would work with saved entities. } 

它抛出以下exception:

collections被修改; 枚举操作可能无法执行。

堆栈跟踪:

在System.Collections.Generic.List的System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource资源)中System.Collections.Generic.List的1.Enumerator.MoveNextRare() at System.Collections.Generic.List System.Data.Objects.ObjectStateManager.PerformAdd的1.Enumerator.MoveNext() (IList 1 entries)
at System.Data.Objects.ObjectStateManager.AlignChangesInRelationships(IList
1 entries)
at System.Data.Objects.ObjectStateManager.AlignChangesInRelationships(IList
1 entries)
at System.Data.Objects.ObjectStateManager.AlignChangesInRelationships(IList
1 entries)
at System.Data.Objects.ObjectStateManager.AlignChangesInRelationships(IList
1条目)处的System.Data.Objects.ObjectStateManager.DetectChanges()处。 System.Data.Entity.Internal.Linq.InternalSet中的System.Data.Entity.Internal.Linq.InternalSet 1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet DetectChanges(布尔强制) 1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet (Object实体)
在System.Data.Entity.DbSet`1.Add(TEntity实体)

任何人都知道发生了什么,也许是如何解决它? 谢谢 !

我有同样的问题。 它看起来像EF中的一个错误。

我将代码更改为在将实体设置为任何其他实体属性之前将实体显式添加到EF上下文。

对我来说,这看起来像是Entity Framework中的一个错误。 我把你的例子简化为一个更简单的例子但具有相同的结构:

 public class TestA // corresponds to your Employee { public int Id { get; set; } public TestB TestB { get; set; } // your Employer } public class TestB // your Employer { public TestB() { TestCs = new List(); } public int Id { get; set; } public ICollection TestCs { get; set; } // your EmployeeRoles } public class TestC // your EmployeeRole { public int Id { get; set; } public TestA TestA { get; set; } // your Employee } 

这些是具有循环关系的三个实体:

 TestA -> TestB -> TestC -> TestA 

如果我现在使用与你的结构相同的相应代码,我得到相同的exception:

 var testA = new TestA(); var testB = new TestB(); var testC = new TestC(); context.TestAs.Add(testA); testA.TestB = testB; testB.TestCs.Add(testC); testC.TestA = testA; context.ChangeTracker.DetectChanges(); 

请注意,我使用了DetectChanges而不是SaveChanges因为exception中的堆栈跟踪清楚地表明实际上DetectChanges导致exception(由SaveChanges内部调用)。 我还发现两次调用SaveChanges不是问题。 这里的问题只是在整个对象图完成之前向上下文添加“早期”。

被修改的集合(作为例外是抱怨) 不是模型中的TestB.TestCs集合。 它似乎是ObjectStateManager的条目集合。 我可以通过在TestB类中用TestC TestC的单个引用替换ICollection TestCs来validation这一点。 这样,模型根本不包含任何集合,但它仍然会针对修改后的集合抛出相同的exception。 (尽管有三个单引用, SaveChanges会失败,因为EF不知道由于循环而以哪种顺序保存实体。但这是另一个问题。)

我认为这是一个错误,EF更改检测( DetectChanges )似乎修改了它自己的内部集合,它正在迭代。

现在,解决这个问题很容易:在调用SaveChanges之前,只需Add实体Add到上下文中作为最后一步:

 var testA = new TestA(); var testB = new TestB(); var testC = new TestC(); testA.TestB = testB; testB.TestCs.Add(testC); testC.TestA = testA; context.TestAs.Add(testA); context.ChangeTracker.DetectChanges(); 

EF将整个相关对象图添加到上下文中。 此代码成功(也使用SaveChanges而不是DetectChanges )。

或者你的例子:

 using (DbContext db = DbContext.GetNewDbContext()){ Employee creator = new Employee("Bob"); Employer employer = new Employer("employer", creator); db.Employees.Add(creator); db.SaveChanges(); } 

编辑

这是相同的例外: 当使用可观察集合时,entity framework抛出“集合被修改” 。 遵循该示例中的代码情况类似:向上下文添加实体,然后更改/添加与该实体的关系。

EDIT2

有趣的是,这引发了同样的exception:

 var testA = context.TestAs.Find(1); // assuming there is already one in the DB var testB = new TestB(); var testC = new TestC(); testA.TestB = testB; testB.TestCs.Add(testC); testC.TestA = testA; context.SaveChanges(); // or DetectChanges, it doesn't matter 

所以,我想将新实体的关系添加到现有实体中。 解决这个问题似乎不太明显。

我最近才遇到这个问题。 我发现EF讨厌间接循环引用。 在您的情况下,雇主应该拥有与员工的关系。 因此,从员工class中取出对雇主的参考。

今天早上我遇到了同样的问题,在我的情况下,我有一个以循环关系定义的“员工 – 经理”协会。 例如:

 public class Employee { public string Name { set; get; } virtual public Employee Manager { set; get; } public Employee() { } } 

设置Manager属性时,应用程序因上述错误而崩溃。 最后,它变成了Employee类中GetHashCode()方法的错误实现 。 由于实体之间的比较失败,EF似乎无法发现修改后的实体; 因此,EF认为该集合已被修改。