2

所以简而言之的场景:我有一个实体(EF4),它有一个外键到同一实体(层次结构)中的主键,例如

MyEntityId(主键) ParentMyEntityId(主键的外键)

如果我有一个 MyEntityList List<MyEntity>,其中两者的 EntityState 都未更改:

entity 1 - {MyEntityId = 10, ParentMyEntityId = null}
entity 2 - {MyEntityId = 11, ParentMyEntityId = 10}

然后我这样做:

//Initially has 2 items in 'in' clause - iterates once and then exits because the EntityState of the second item has changed to Modified
foreach(MyEntity m in MyEntityList.Where(e => e.EntityState == System.Data.EntityState.Unchanged))
{
     db.DeleteObject(m);
}

第一个 MyEntity 被删除,但第二个更改为“Modified”,并且 foreach 没有第二次运行 - 我猜是由于外键约束。

但是,如果我这样做:

//Iterates twice, even though the EntityState of the second item has changed to Modified
foreach(MyEntity m in MyEntityList.Where(e => e.EntityState == System.Data.EntityState.Unchanged).ToList())
{
     db.DeleteObject(m);
}

两个实体都被删除(这是预期的效果)。

虽然我有一个解决方案,但我对为什么会发生这种情况很感兴趣,我总是觉得在 foreach 循环开始时定义的迭代器“set”保持不变,或者如果你尝试抛出运行时错误修改它。

我不应该使用 Where 吗?有一个更好的方法吗?

4

1 回答 1

1

迭代器集是在循环运行之前定义的,因为您执行ToList(如果您不这样做,它将不会被很好地定义)。

所以迭代源是恒定的。但不是您迭代的对象。您获得的对象引用是常量,但不是它们指向的对象。

没有 ToList 的版本等价于:

foreach(MyEntity m in MyEntityList) //always 2 items
{
     //loop body always called two times
     if (e.EntityState == System.Data.EntityState.Unchanged) //2 times
        db.DeleteObject(m); //1 time
}

ToList 版本等价于:

var copy = MyEntityList.Where(e => e.EntityState == System.Data.EntityState.Unchanged).ToList(); //always 2 items
foreach(MyEntity m in copy)
{
     //loop body always called two times
     db.DeleteObject(m); //2 times
}
于 2012-08-18T14:10:07.197 回答