实体框架ObjectContext.SaveChanges在唯一键列更新时失败

时间:2011-10-15 15:32:59

标签: asp.net-mvc-3 entity-framework unique-key

考虑非常简单的数据库表:

CREATE TABLE UkTest(
  id int NOT NULL,
  uk int NOT NULL
)
Primary Key on id
Unique Key on uk

然后添加2行:

INSERT INTO UkTest (id,uk) VALUES(1,1);
INSERT INTO UkTest (id,uk) VALUES(2,2);

然后进行2次测试。

行:

var db =  new Database1Entities();
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);

element1.uk = 0;
element2.uk = 1;  // overrides previous element1.uk value
var count = db.SaveChanges();

失败(在测试之前将uk值恢复为1和2!):

var db =  new Database1Entities();
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);

element2.uk = 0;
element1.uk = 2;  // overrides previous element2.uk value
var count = db.SaveChanges();
// Cannot insert duplicate key row in object 'dbo.UkTest' with unique index 'UK_UkTest'

请参阅ObjectContext.SaveChanges()按主索引的顺序检查行。

有没有办法强迫自己订购?

2 个答案:

答案 0 :(得分:2)

除非你两次调用SaveChanges(),否则无法控制实体框架将发送到数据库的SQL语句的顺序。您可以将多个SaveChanges()调用包装到外部事务中,以确保整个操作仍然是事务性行为:

using (var scope = new TransactionScope())
{
    using (var db = new Database1Entities())
    {
        var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
        var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);

        element2.uk = 0;
        db.SaveChanges();

        element1.uk = 2;
        db.SaveChanges();
    }
    scope.Complete();
}

答案 1 :(得分:0)

感谢Slauma。我找到了解决方案。关键是将元素保存在几个ObjectContext实例中。

public class SavingElementsWithTransactionInOwnOrder
{
    public void SaveElements ()
    {
        var db = new Database1Entities();
        var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
        element1.db = db;

        db = new Database1Entities();
        var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);
        element2.db = db;

        element2.uk = 0;
        element1.uk = 2;

        var scope = new TransactionScope();
        try{
            element2.db.SaveChanges();
            element1.db.SaveChanges();
            scope.Complete();
        }
        finally{
            scope.Dispose();
        }
    }
}

public partial class UkTest
{
    public Database1Entities db { get; set; }
}