如何处理UpdateException - '违反PRIMARY KEY约束'实体框架?

时间:2014-04-08 16:00:52

标签: c# sql entity-framework

我有一个允许多个用户的应用程序和一个具有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;
    }
}

但是我在" //处理这里"部分。我尝试刷新对象,但它在"添加"国家和因此不能刷新。 我要做的是:确认已经存在具有这些ID的对象,删除它想要插入的对象并从数据库加载现有对象。 我怎么能这样做?

4 个答案:

答案 0 :(得分:2)

因为我得到了一个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;
}

答案 1 :(得分:1)

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

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对象,以使其成为错误号... < / p>

答案 2 :(得分:0)

  

因此,当2个用户尝试使用相同的ID向此表格添加条目时   由于主键constaint,其中一个获取UpdateException   冲突。

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

  

我要做的是:承认已有一个物体   使用这些ID,删除它想要插入的对象并加载   来自数据库的现有对象。

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

  • 我们必须先知道你应该如何建议 &#34;应答&#34;
  • 放弃物体很容易 - 你不能这样做 其他任何事情。
  • 最后,您要加载现有对象。 这有必要吗?一旦它是什么,你打算用它做什么 装?让我们说你想用它来更新现有的对象 传递的价值(我不会,但让我们说你需要的是什么 做)。您需要做的就是将其从DB读取为新的 对象,更新要更改的字段,然后保存。

这是一个可能的例子:

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."

答案 3 :(得分:0)

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

而不是仅仅尝试将更改写入数据库,然后在收到错误时处理冲突的主键约束,在写入之前检查具有相关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是你的数据库变量...... 希望这对你有帮助!