How to ignore a DbUpdateConcurrencyException when deleting an entity

*爱你&永不变心* 提交于 2020-01-10 08:54:09

问题


I have an app that reads a lot of data into memory and processes it in a batches.

What I want is for entity framework to ignore DbUpdateConcurrencyException when deleting an entity that has already been deleted.

The reason is that by the time an entity has been processed and marked for deletion, it may already have been deleted from the DB.

Obliviously deleting a row that has already been deleted isn't a problem and shouldn't cause an error, I just need a way to tell entity framework that :)

Example

Db.Entry(itemToRemove).State = EntityState.Deleted;
Db.SaveChanges();

Causes an error if itemToRemove has already been deleted.

Note: Db.Configuration.ValidateOnSaveEnabled = false; doesn't fix this as another thread suggested.


回答1:


How about?

Db.Entry(itemToRemove).State = EntityState.Deleted;

bool saveFailed;
do
{
    saveFailed = false;
    try
    {
       Db.SaveChanges();
    }
    catch(DbUpdateConcurrencyException ex)
    {
       saveFailed = true;
       var entry = ex.Entries.Single();
       //The MSDN examples use Single so I think there will be only one
       //but if you prefer - do it for all entries
       //foreach(var entry in ex.Entries)
       //{
       if(entry.State == EntityState.Deleted)
          //When EF deletes an item its state is set to Detached
          //http://msdn.microsoft.com/en-us/data/jj592676.aspx
          entry.State = EntityState.Detached;
       else
          entry.OriginalValues.SetValues(entry.GetDatabaseValues());
          //throw; //You may prefer not to resolve when updating
       //}
    }
} while (saveFailed);

More here: Resolving optimistic concurrency exceptions




回答2:


You could handle the DbUpdateConcurrencyException and then call Refresh(RefreshMode,IEnumerable) with RefreshMode.StoreWins and your deleted entities as parameter.

try{
  Db.Entry(itemToRemove).State = EntityState.Deleted;
  Db.SaveChanges();
}
catch(DbUpdateConcurrencyException)
{
  IObjectContextAdapter adapter = Db;

  adapter.ObjectContext.Refresh(RefreshMode.StoreWins, context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Deleted));
  Db.SaveChanges();
}



回答3:


Based on the code from https://msdn.microsoft.com/en-US/data/jj592904 but where I added an infite loop counter (just in case, you never know, right?) and looping through all the entries in the exception's list.

var maxTriesCounter = 20;
bool saveFailed;
do
{
    saveFailed = false;
    maxTriesCounter--;
    try
    {
        context.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        saveFailed = true;
        foreach (var entry in ex.Entries)
        {
            entry.Reload();
        }
    }
} while (saveFailed && maxTriesCounter > 0);



回答4:


Here is what I use. Detach all problem records after the save.

Db.Entry(itemToRemove).State = EntityState.Deleted;

while(true)
    try {
        Db.SaveChanges();
        break;
    } catch (DbUpdateConcurrencyException ex) {
        ex.Entries.ToList().ForEach(x=>x.State=EntityState.Detached);
    }

Or you could add a custom SaveChanges function to your DbContext class and use it instead whenever you need to ignore those errors.

    public int SaveChanges_IgnoreConcurrencyExceptions  () {
        while(true)
            try {
                return this.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
                ex.Entries.ToList().ForEach(x => x.State=EntityState.Detached);
            }
    }


来源:https://stackoverflow.com/questions/19295232/how-to-ignore-a-dbupdateconcurrencyexception-when-deleting-an-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!