2017-05-30 108 views
1

在我的C#程序中,我使用實體框架將本地SQL Server數據庫與QuickBooks數據同步。從QuickBooks獲取數據似乎沒有任何問題。然而,我在進行實體的批量提交時遇到了一個絆腳石。實體框架 - 如何處理批量SaveChanges失敗

目前我正在用可配置數量的實體構建DataContext,然後批量提交實體。到目前爲止批次沒有失敗,但如果它確實如此呢?我想解決這個問題的方法是迭代批處理,並一次提交一個實體,然後記錄導致提交失敗的那個實體。

但是我沒有看到用數據上下文做這件事的方法,因爲它在使用SaveChanges()時似乎是全部或無關緊要的。是否有辦法處理我想要完成的任務,還是應該以完全不同的方式處理故障?

這裏是我目前擁有的代碼,如果你想看看它:

int itemsCount = 0; 
int itemsSynced = 0; 
int itemsFailed = 0; 

ArrayList exceptions = new ArrayList(); 

int batchSliceCount = Properties.Settings.Default.SyncBatchSize; //Getting the max batch size from the settings 
int index = 1; //Index used for keeping track of current batch size on data context 
List<Customer> currentBatch = new List<Customer>(); // List to hold curent batch 

db = new DataContext(DatabaseHelper.GetLocalDatabaseConnectionString()); 

foreach (var customer in QBResponse.customers) 
{ 
    itemsCount++; 

    try 
    { 
     string debugMsg = "Saving Customer with the Following Details....." + Environment.NewLine; 
     debugMsg += "ListId: " + customer.CustomerListId + Environment.NewLine; 
     debugMsg += "FullName: " + customer.FullName + Environment.NewLine; 
     int progressPercentage = (itemsCount * 100)/opResponse.retCount; 
     UpdateStatus(Enums.LogLevel.Debug, debugMsg, progressPercentage); 

     var dbCustomer = db.Customers.FirstOrDefault(x => x.CustomerListId == customer.CustomerListId); 

     if (dbCustomer == null) 
     { 
      // customer.CopyPropertiesFrom(customer, db); 
      Customer newCustomer = new Customer(); 
      newCustomer.CopyCustomer(customer, db); 
      newCustomer.AddBy = Enums.OperationUser.SyncOps; 
      newCustomer.AddDateTime = DateTime.Now; 
      newCustomer.EditedBy = Enums.OperationUser.SyncOps; 
      newCustomer.EditedDateTime = DateTime.Now; 
      newCustomer.SyncStatus = true; 

      db.Customers.Add(newCustomer); 
      currentBatch.Add(newCustomer); 
     } 
     else 
     { 
      //dbCustomer.CopyPropertiesFrom(customer, db); 
      dbCustomer.CopyCustomer(customer, db); 
      dbCustomer.EditedBy = Enums.OperationUser.SyncOps; 
      dbCustomer.EditedDateTime = DateTime.Now; 
      dbCustomer.SyncStatus = true; 
      currentBatch.Add(dbCustomer); 
     } 

     try 
     { 
      if (index % batchSliceCount == 0 || index == opResponse.customers.Count()) //Time to submit the batch 
      { 
       UpdateStatus(Enums.LogLevel.Information, "Saving Batch of " + batchSliceCount + "Customers to Local Database"); 
       db.SaveChanges(); 
       itemsSynced += currentBatch.Count(); 
       currentBatch = new List<Customer>(); 
       db.Dispose(); 
       db = new DataContext(DatabaseHelper.GetLocalDatabaseConnectionString()); 
      } 
     } 
     catch (Exception ex) 
     { 
      string errorMsg = "Error occured submitting batch. Itterating and submitting one at a time. " + Environment.NewLine; 
      errorMsg += "Error Was: " + ex.GetBaseException().Message + Environment.NewLine + "Stack Trace: " + ex.GetBaseException().StackTrace; 
      UpdateStatus(Enums.LogLevel.Debug, errorMsg, progressPercentage); 

      //What to do here? Is there a way to properly iterate over the context and submit a change one at a time? 
     } 
    } 
    catch (Exception ex) 
    { 
     //Log exception and restart the data context 
     db.Dispose(); 
     db = new DataContext(DatabaseHelper.GetLocalDatabaseConnectionString()); 
    } 

    Thread.Sleep(Properties.Settings.Default.SynchronizationSleepTimer); 
    index++; 
} 
+0

確實難以解決的問題,這就是我會做的......如果SaveChanges出現異常,我會嘗試將內容寫入日誌,以便至少所做的更改仍然可用。然而,EF應該照顧這項權利,因爲它具有「跟蹤」能力。我從來沒有必須與恢復工作,所以我只是想在這裏大聲。 –

回答

0

這取決於你想從收回的例外......

如果您正在尋找一種方法來重試連接是否中斷,您可以使用自定義執行策略基於DbExecutionStrategy,如果發生特定錯誤,如CodeProject文章中所述,則重試。

+0

我知道使用執行策略來處理超時。我還沒有實施它,但它在發展路線圖上。我更關心異常,例如關鍵違規(I.E.正在提交的實體批處理被SQL Server拒絕)。 – Stephen

+0

,因爲沒有辦法重試可以解決密鑰違規錯誤我建議您在嘗試將其安全地存儲到商店之前自行驗證批處理 – user1859022