删除实体时如何忽略DbUpdateConcurrencyException

her*_*ist 15 entity-framework

我有一个应用程序,它将大量数据读入内存并批量处理.

我想要的是实体框架DbUpdateConcurrencyException在删除已删除的实体时忽略.

原因是,当一个实体被处理并标记为删除时,它可能已经从数据库中删除.

不经意地删除已经删除的行不是问题,不应该导致错误,我只需要一种方法告诉实体框架:)

Db.Entry(itemToRemove).State = EntityState.Deleted;
Db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

如果itemToRemove已被删除则导致错误.

注意:Db.Configuration.ValidateOnSaveEnabled = false;不会修复此问题,因为另一个线程建议.

Col*_*lin 15

怎么样?

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);
Run Code Online (Sandbox Code Playgroud)

更多信息: 解决乐观并发异常


her*_*ist 5

I posted this question a long time ago but it has recently had some attention so I though I would add the solution I actually use.

//retry up to 5 times
for (var retries = 0; retries < 5; retries++)
{
    try
    {
        Db.SaveChanges();
        break;
    }
    catch (DbUpdateConcurrencyException ex)
    {
        foreach (var entity in ex.Entries)
        {
            entity.State = EntityState.Detached;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Things I considered - I did NOT want to use ReloadAsync() or ObjectContext.Refresh as I wanted to ignore items deleted in another process WITHOUT any additional database overhead. I added in the for loop as a simple protection against infinite loops - not something that should be able to happen, but I'm a belt and braces approach man and not a fan of while(true) if it can be avoided. No need to a local variable like isDone or saveFailed - simply break if we saved successfully. No need to cast ex.Entries to a list in order to enumerate it - just because you can write something on one line doesn't make it better.