删除行时如何避免乐观并发异常?

时间:2017-11-19 10:17:32

标签: c# optimistic-concurrency ef-core-2.0

我有一个方法可以接收要删除的某些行的ID。我正在使用这样的代码:

public bool delete(IEnumerable<long> paramIeId)
{
    using(myContext)
    {
        foreach(long iterator in paramIeId)
        {
            nyDbContext.Remove(new MyType(){ID = iterator});
        }
    }
}

它工作正常,因为存在时删除行。但是如果区域中有1行或更多行不存在,那么我会得到一个异常并且没有一行被删除,尽管其中一些行存在。

如果我在T-SQL中执行此查询,我没有遇到问题,数据库会删除现有的行并且不会显示现有行,因为最后我想删除它们,以便其他进程为我删除它们没问题。

我可以处理刷新dbContextfrom数据库的乐观并发异常,但我认为这是可以避免的额外查询。

EF有什么方法可以像T-SQL一样工作吗?如果我尝试删除一个不存在的行,请忽略它并删除其余的行。

感谢。

2 个答案:

答案 0 :(得分:2)

您不需要创建新对象来删除它,只需让EF为您处理所有事情:

public bool delete(IEnumerable<long> paramIeId)
{
    using(var nyDbContext = new DbContext())
    {
        foreach(long id in paramIeId)
        {
            MyType myType = nyDbContext.MyTypes.FirstOrDefault(x => x.ID == id);
            if (myType != null)
            {
                nyDbContext.MyTypes.Remove(myType);
            }
        }
        nyDbContext.SaveChanges();
     }
}

答案 1 :(得分:1)

至少目前,使用分离的实体执行删除时,异常似乎是不可避免的。您必须使用try / catch并处理异常或查询数据库以匹配ID,并且只删除匹配 1

具有异常处理的示例

using (myContext)
{
    foreach (long iterator in paramIeId)
    {
        nyDbContext.Remove(new MyType() { ID = iterator });
    }

    try
    {
        nyDbContext.SaveChanges()
    }
    catch(DbUpdateConcurrencyException ex)
    {
        //if you want special handling for double delete
    }
}

带有查询的示例,然后删除

请注意,我在循环之前查询整个类型列表,以避免对每种类型进行单独的查询。

using (myContext)
{
    var existingMyTypes = nyDbContext.MyTypes.Where(x => paramIeId.Contains(x.ID));
    foreach (MyType existing in existingMyTypes)
    {
        nyDbContext.Remove(existing);
    }

    nyDbContext.SaveChanges();
}

1 注意:查询然后删除选项会打开一个可能的竞争条件,这可能会触发您尝试的OptimisticConcurrencyException - 即,如果是另一个进程/线程/程序删除您自己的进程的读取和删除之间的行。完全处理这种可能性的唯一方法是在try / catch中处理异常。