【问题标题】:How can i ignore a DbUpdateConcurrencyException with my Entity Framework code?如何使用我的实体框架代码忽略 DbUpdateConcurrencyException?
【发布时间】:2011-06-28 18:54:47
【问题描述】:

有什么方法可以告诉 EF 不要担心 DELETEUPDATE 做或不做的行数?

我正在尝试从数据库中删除一行,但由于该行不存在,EF 抛出异常:DbUpdateConcurrencyException .. 说0 行受到影响。这是正确的-> 没有删除任何行。但这完全没问题..因为没有数据。

我真的不想往返数据库以查看该行是否存在..如果存在..然后尝试删除它。

如果我尝试在try / catch 块中吞下异常,那么当我尝试SaveChanges() 时,其余要删除的项目不会发送到数据库......这很糟糕。

例如。

Delete(new Foo(1));
Delete(new Foo(2));
Delete(new Foo(3));
SaveChanges(); // <-- Throws the exception.

// DB Trace : DELETE FROM Foo WHERE Id = 1;

就是这样.. 没有任何痕迹显示记录 2 或 3 试图被删除.. 因为异常停止了一切:(

有什么想法吗?

更新

Delete 是如何工作的?这是代码...(简化和强类型)

public void Delete(Foo foo)
{
    if (foo == null)
    {
        throw new ArgumentNullException("foo");
    }

    Foo attachedEntity = Context.Set<Foo>().Local.FirstOrDefault(x => x.Id > 0);

    if (attachedEntity != null)
    {
        // Entity already in object graph - remove entity.
        Context.Set<Foo>().Remove(attachedEntity);
    }
    else
    {
        // Entity not in object graph, attach and set EntityState to Deleted.
        Context.Entry(foo).State = EntityState.Deleted;
    }
}

【问题讨论】:

  • 删除功能如何工作?
  • @LukLed - 使用额外代码编辑了 OP。
  • 我知道这些删除是更大操作的一部分,不能独立进行?
  • 即使它们是独立制作的,也存在同样的问题 -> 尝试删除数据库中不存在的 DETACHED 对象。我不在乎该行是否存在-> 只是尝试删除它。如果它不存在,则没有问题。如果是,则删除。完毕。 /me 打 EF。
  • 找到解决方案了吗?在单个 SaveChanges 调用中执行多个操作时,这是一个很大的痛苦。

标签: .net entity-framework entity-framework-ctp5


【解决方案1】:

您实际上可以通过设置忽略这些类型的问题:

db.Configuration.ValidateOnSaveEnabled = false;

db 是 DbContext 实例。

显然,当您执行此操作时,您应该知道自己在做什么,但话又说回来,大多数更新非 EF 数据库的方法没有任何更改跟踪/验证,只需向数据库天真地没有先检查任何东西,所以你基本上只是告诉 EF 表现得更像那样。

【讨论】:

  • 你确定吗? ValidateOnSaveEnabled 控制数据注释验证,而不是并发。我的理解是(从 EF 4.3 开始)没有办法禁止删除 DbUpdateConcurrencyValidation。
  • 我在发布之前测试了上述声明;我创建了 2 个 DbContext,一个用于获取对象,另一个用于获取、更改和保存对象,最后尝试更改并保存第一个。我有一个例外;把上面的设置改成false,再次运行,没有异常。另外,你检查过文档吗?它指的是验证实体,而不是模式:msdn.microsoft.com/en-us/library/…
  • 不起作用,DbUpdateConcurrencyException 仍然被抛出。我用 2 个 DbContexts 实例进行了测试。在第一个中编辑了一个实体并将ValidateOnSaveEnabled 设置为false,然后在第二个上下文中删除该实体并保存,然后在第一个上下文中保存,但它引发了异常。
【解决方案2】:

我认为 EF 的行为是正确的 - 只是您必须仅对 DB 中存在的对象执行命令。它不适用于以下场景:“我会尝试,我们会看到......”。如果你不能确定对象存在于数据库中并且你不想做往返(我认为这是最好的主意,因为删除分离的对象可能有其他几个陷阱,特别是如果对象参与独立关联)你应该使用DbContext.Database.SqlCommand 并运行存储过程。

here 描述了处理 DbUpdateConcurrencyException 的正确方法 => 在每个异常之后,您应该解决冲突(在您的情况下,这意味着从 DbContext 中删除有问题的实体)并再次执行 SaveChanges

【讨论】:

  • Ah :) 今天早些时候,我正在尝试在 Context.SaveChanges() 周围使用 try/catch 来处理任何 DbUpdateConcurrencyException 异常 .. 但我所做的只是 Refresh() .. 然后 SaveChanges () 再次..这当然不起作用(抛出了同样的错误)。您能否更新您的答案以包括您如何从上下文中删除违规实体?
  • @Pure.Krome:我会尝试使用 ChangeTracker 并将实体状态设置为 Detached。
  • 能否请您详细说明您之前的评论?
  • @Pure.Krome:尝试使用exception.GetEntry(dbContext).State = EntityState.Detached; 捕获异常的地方DbUpdateConcurrencyException。如果这不起作用,您只需在将其标记为已删除之前检查该实体是否存在。
  • 我不同意这个答案,EF 的行为是不正确的。这样想 - 用户 A 选择,存在。用户 B 确实存在,存在。用户A删除,成功。用户 B 删除,异常失败。在这两种情况下,结果应该是相同的——我们正在删除记录。当然,有冲突,但结果是一样的 - 删除的行。没有什么要解决的。 “首先检查它是否存在”不起作用 - 这是一个竞争条件。不能在所有情况下都锁定读取,在我们的例子中,我们使用的是 MySQL 集群 - 没有读取锁。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 2013-10-18
  • 2022-11-21
  • 2012-02-12
  • 2011-12-14
  • 2012-05-18
  • 1970-01-01
相关资源
最近更新 更多