2012-05-23 72 views
9

当我使用以下代码遍历一个foreach时,它成功捕获发生的第一个异常,并将该id添加到我的错误列表中。在循环的所有后续迭代中,它将继续捕获以前的异常。实体框架;如何处理foreach循环中的异常并继续迭代

如何正确捕获异常并撤消或清除失败的DeleteObject请求,以便可以执行后续删除。

public ActionResult Delete(int[] ListData) 
{ 
    List<int> removed = new List<int>(); 
    List<int> error = new List<int>(); 
    Item deleteMe; 
    foreach (var id in ListData) 
    { 
     deleteMe = this.getValidObject(id); 
     if (deleteMe == null) 
     { 
      error.Add(id); 
      continue; 
     } 

     try 
     { 
      this.DB.Items.DeleteObject(deleteMe); 
      this.DB.SaveChanges(); 
      removed.Add(id); 
     } 
     catch (DataException ex) 
     { 
      // revert change to this.DB.Items? 
      error.Add(id); 
     } 
    } 
    if (error.Count > 0) 
    { 
     return Json(new { Success = false, Removed = removed, Error = error }); 
    } 
    return Json(new { Success = true, Removed = removed }); 
} 

我已搜查SO和谷歌,大多数人首先会处理全部删除对象,然后保存更改,以便它是一个交易。但我需要它来单独处理每个事务,因此单个故障不会停止其余事务。

我使用实体框架4.

我得到所造成的外键这个特定的例子唯一的例外是关联到被删除的项目。在生产过程中,我将处理这种情况,无论发生什么异常,它都应该能够继续。

+0

什么是ListData?一个'List <>'或者'IQueryable <>'? –

+0

我已更新代码以显示更多上下文。 – SidewaysGravity

回答

7

我假定在this.getValidObject(id)中使用相同的上下文this.DB来检索实体。如果是这种情况,则在异常块调用中:this.DB.detach(deleteme)。这应该阻止SaveChanges()尝试在下一次迭代中删除有问题的实体。

+0

是的,它使用相同的上下文。分离工作很好,实施起来很简单。谢谢 – SidewaysGravity

+0

对于EF4及更新版本,请阅读http://stackoverflow.com/q/4168073/37760了解如何访问Detach方法。 – Corin

0

您提供的代码看起来不错。你看到什么错误?正如你所指出的,也许你需要在这个.DB.Items中取消标记某些东西,尽管我不这么认为。您也可以尝试为每个循环创建一个新的DataContext,以使旧的,失败的DataContext在世界上的状态不相关。

+0

是否可以取消标记更改,以便在异常后下一次调用SaveChanges时不会再次尝试删除前一项并重新抛出异常。我会尝试创建一个新的数据上下文,看看是否有效。 – SidewaysGravity

0

如果我理解正确,不能删除实体(Item),因为它有一个外键关联(子对象)。
您将首先必须使用要删除的父项(项目)更新所有子项(相关)实体,方法是删除关系,更新实体以使其与备选父项(项目)相关联或删除子实体(实体)然后最终删除父项(Item)实体。

+0

是的,我明白这一点,并且会为此做好这一点。但是,如果有任何形式的异常,我希望能够继续迭代,并且有可能我将无法正确处理异常,在这种情况下,我只会通知用户它不能被删除到一个错误。 – SidewaysGravity