2011-10-15 85 views
1

考慮非常簡單的數據庫表:實體框架ObjectContext.SaveChanges上唯一鍵列更新失敗

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次測試。

OK:

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

除非您撥打SaveChanges()兩次,否則沒有辦法控制Entity Framework將發送到數據庫的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(); 
} 
+0

謝謝,很多。不幸的是我的例子被簡化了我會盡量發佈更難的。 – xymyk

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; } 
}