Entity Framework - 如何处理批量保存更改失败

Entity Framework - How To Handle Batch SaveChanges Failure

在我的 C# 程序中,我使用 Entity Framework 将本地 SQL 服务器数据库与 QuickBooks 数据同步。从 QuickBooks 获取数据似乎没有任何问题。但是,在进行实体的批量提交时,我 运行 陷入了绊脚石。

目前,我正在使用可配置数量的实体构建 DataContext,然后批量提交这些实体。到目前为止,该批次还没有失败,但如果失败了怎么办?我解决这个问题的想法是遍历批次并一次提交每个实体,然后记录 is/are 导致提交失败的实体。

但是我看不到一种方法可以对数据上下文执行此操作,因为在使用 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++;
 }

这取决于您要从中恢复的异常...

如果您只是想寻找一种在连接中断时重试的方法,您可以使用基于DbExecutionStrategy that retries if specific errors occur as demonstrated in this CodeProject文章的自定义执行策略