如何在Entity Framework上处理UpdateException – “违反PRIMARY KEY约束”?

我有一个允许多个用户的应用程序和一个具有2个ID作为复合键的数据库表。 这些ID也是来自另一个表的外键。 因此,当2个用户尝试使用相同的ID向此tabel添加条目时,由于主键违反规则,其中一个用户会获得UpdateException。 我已经发现它应该像这样处理:

try { result = base.SaveChanges(options); } catch (UpdateException ex) { SqlException innerException = ex.InnerException as SqlException; if (innerException != null && innerException.Number == 2627 || innerException.Number == 2601) { // handle here } else { throw; } } 

但是我在“// Handle here”部分实际上做了什么。 我尝试刷新对象,但它处于“已添加”状态,因此无法刷新。 我要做的是:确认已经存在具有这些ID的对象,删除它想要插入的对象并从数据库加载现有对象。 我怎样才能做到这一点?

自从我得到了一个upvote,我回顾了我是如何解决这个问题的。 所以这就是我所做的:

 // Exception number 2627 = Violation of %ls constraint '%.*ls'. Cannot insert duplicate key in object '%.*ls'. // Exception number 2601 = Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. // See http://msdn.microsoft.com/en-us/library/cc645603.aspx for more information and possible exception numbers if (innerException != null && (innerException.Number == 2627 || innerException.Number == 2601)) { // Resolve the primary key conflict by refreshing and letting the store win // In order to be able to refresh the entity its state has to be changed from Added to Unchanged ObjectStateEntry ose = ex.StateEntries.Single(); this.ObjectStateManager.ChangeObjectState(ose.Entity, EntityState.Unchanged); base.Refresh(RefreshMode.StoreWins, ose.Entity); // Refresh addedChanges now to remove the refreshed entry from it addedChanges = this.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Where(s => !s.IsRelationship); } else { throw; } 

我必须使用以下内容才能为我工作 – 我使用的是异步function,但我已经过测试,它可以在没有异步的情况下工作…

 try { await db.SaveChangesAsync(); } catch (DbUpdateException ex) { SqlException innerException = ex.InnerException.InnerException as SqlException; if (innerException != null && (innerException.Number == 2627 || innerException.Number == 2601)) { //your handling stuff } else { throw; } } 

我发现,如果我没有使用DbUpdateException,它只是直接传递给catch,我的ex.InnerException和我潜入的另一个InnerException对象,以使其成为错误号…

因此,当2个用户尝试使用相同的ID向此tabel添加条目时,由于主键违反规则,其中一个用户会获得UpdateException。

正确 – 如果您有一个主键(无论是1列还是多列),它必须是唯一的。

我要做的是:确认已经存在具有这些ID的对象,删除它想要插入的对象并从数据库加载现有对象。

这有点难以回答,因为我们不知道这个方法应该返回的内容等等。

  • 我们必须先知道你应该如何“确认”。
  • 丢弃对象很容易 – 你只是不做任何其他事情。
  • 最后,您要加载现有对象。 这有必要吗? 加载后你打算用它做什么? 假设您希望使用传入的值更新现有对象(我不会,但让我们说这就是您需要做的事情)。 您需要做的就是将数据库中的数据读入新对象,更新要更改的字段然后保存。

这是一个可能的例子:

 var exisitingEntity = context.TheEntity; existingEntity.Property1 = options.Property1; existingEntity.Property2 = options.Property2; ... context.SaveChanges(existingEntity); return "Object already existed, but was updated with the values passed in." 

除非我完全误解了你想要做的事情,否则我认为你可能会从错误的方向解决这个问题。

当你收到错误时,不只是尝试将更改写入数据库,然后处理冲突的主键约束,在写入之前检查具有相关Id的对象,如果存在则处理,如果不存在,则继续正常:

 if(base.object.Any(o=> o.Id == command.Id){ ///Object exists, your "// handle here" goes here... }else{ ///No such object, save your changes normally } 

假设base是你的数据库变量…希望这可能对你有帮助!