2012-05-23 110 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