2011-07-15 19 views
2

我有一種情況,我創建一個表中的記錄(asset_type),並通過第二個表(資產)中的外鍵引用它。在這種情況下,這兩個插入都發生在同一個TransactionScope中。爲什麼使用EF代碼的插入首先在TransactionScope中失敗?

當使用原始的DbConnection,插入成功:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw";  

using (var trans = new TransactionScope()) 
{ 
    conn.Open(); 
    conn.EnlistTransaction(Transaction.Current); 

    var cmd = conn.CreateCommand(); 
    cmd.CommandText = "INSERT INTO overview.asset_type (name) VALUES('Unknown') RETURNING id"; 
    var assetTypeId = (int)cmd.ExecuteScalar(); 

    cmd.CommandText = string.Format("INSERT INTO overview.asset " 
            + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) " 
            + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0) " 
            + "RETURNING id ", assetTypeId); 
    var assetId = (int)cmd.ExecuteScalar(); 

    trans.Complete(); 
} 

但是,如果我切換到使用的DbContext類,第二個插入(成資產)失敗,一個違反外鍵約束,就好像第一次插入(進入asset_type)沒有發生:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw"; 

using (var trans = new TransactionScope()) 
{ 
    using (var context = new TestContext(conn, false)) 
    { 
    var assetTypeId = context.Database 
     .SqlQuery<int>("INSERT INTO overview.asset_type (name) VALUES('Unknown') RETURNING id") 
     .Single(); 

    var assetId = context.Database 
     .SqlQuery<int>(string.Format("INSERT INTO overview.asset " 
            + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) " 
            + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0) " 
            + "RETURNING id ", assetTypeId)) 
     .Single(); 
    trans.Complete(); 
    } 
} 

如果我刪除了TransactionScope,則DbContext示例正常執行。

我試着玩IsolationLevel設置(ReadCommitted,ReadUncommitted)沒有成功。

我意識到我不需要在這個例子中的TransactionScope。這是涉及與多個數據庫交互並需要分佈式事務的較大塊代碼的一部分。

我的數據庫是PostgreSQL,我使用的是DevArt的dotConnect .NET驅動程序。

有沒有人有任何洞察,爲什麼DbContext示例不起作用?

+0

我從來沒有真正使用過DbContext的原始SQL方法,但對於DML(如INSERT,UPDATE,DELETE)而言,「SqlQuery」僅用於READ操作(查詢)和'ExecuteSqlCommand'嗎?但是,我很驚訝你沒有得到例外。 – Slauma

+1

我測試了一個類似的代碼(但是相同的邏輯:在table1中插入row1,然後將table2中的row2插入到row1的FK中),SQL Server和SQLClient作爲提供程序。它既可以使用也可以不使用'TransactionScope'。這個問題可能與PostgreSQL或dotConnect驅動程序有關。 – Slauma

回答

0

Managing Connections and Transactions

實體框架打開的連接只有在需要時,例如執行查詢或打電話的SaveChanges,然後關閉連接時,操作完成。

  • 調用任何下列方法打開連接:
  • 的SaveChanges或刷新上ObjectContext的。
  • FirstOrDefault或ObjectQuery上的第一個。
  • 在EntityCollection上加載。
  • 在EntityReference上加載。
  • 任何語言集成查詢(LINQ)方法或ObjectQuery查詢生成器方法,例如Where,OrderBy或Select。

然後它打開另一個連接,事務範圍拋出異常。您必須設置Distributed Transaction Coordinator(不能說它是真實的或不適用於PostgreSQL)。

如果它是真實的,那麼在設置DTC後,只需在範圍內打開conn對象。

+0

我明白了,所以在上下文的範圍內手動管理連接生存期? –

+0

@Chris Hogan是的,如果交易範圍是必需的。 – VMAtm