2011-07-15 10 views
2

私は1つのテーブル(asset_type)にレコードを作成し、2番目のテーブル(アセット)の外部キーを使ってレコードを参照する状況があります。この状況では、これらの挿入は両方とも同じ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クラスの使用に切り替える場合は、(資産への)2番目の挿入が外部キー制約違反で失敗したかのように最初の挿入(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(); 
    } 
} 

DbContextの例は正常に実行されます。

IsolationLevelの設定(ReadCommitted、ReadUncommitted)で再生しようとしましたが、成功しませんでした。

私はこの例ではTransactionScopeは必要ないことを認識しています。これは、複数のデータベースとのやりとりや分散トランザクションが必要な、より大きなコードの一部です。

私のデータベースはPostgreSQLであり、DevArtのdotConnect .NETドライバを使用しています。

誰かがDbContextの例が機能しない理由についての洞察はありますか?

+0

DbContextの生のSQLメソッドを実際に使ったことはありませんでしたが、READ操作(クエリ)でのみ 'SqlQuery'でなく、INSERT、UPDATE、DELETEのようにDMLで' ExecuteSqlCommand'ですか?しかし、私はあなたが例外を取得しないことに驚いています。 – Slauma

+1

SQL ServerとSQLClientをプロバイダとして使用して、同様のコードをテストしました(ただし、同じロジック:table1にrow1を挿入し、row2をrow1にFKでtable2に挿入)。 'TransactionScope'の有無にかかわらず動作しました。この問題は、PostgreSQLまたはdotConnectドライバと関係している可能性があります。 – Slauma

答えて

0

Managing Connections and Transactions

Entity Frameworkのは、必要な、例えばクエリを実行するか、SaveChangesメソッドを呼び出す場合にのみ接続を開き、その後、操作が完了した接続を閉じます。

  • のSaveChangesをかのObjectContextにリフレッシュ:以下のいずれかの方法を呼び出す

    • は、接続を開きます。
    • FirstOrDefault、またはFirst on ObjectQuery。
    • EntityCollectionに読み込みます。
    • EntityReferenceにロードします。
    • Language-Integrated Query(LINQ)メソッドまたはObjectQueryクエリビルダーメソッド(Where、OrderBy、Selectなど)。

    そして、もう1つの接続、トランザクションスコープスロー例外が開きます。 Distributed Transaction Coordinatorを設定する必要があります(PostgreSQLでは実際のものかどうかはわかりません)。

    実際の場合は、セットアップ後にDTCが範囲内のconnオブジェクトを開くだけです。

    +0

    私は、コンテキストの範囲内で手動で接続の有効期間を管理していますか? –

    +0

    @Chris Hoganはい、トランザクションスコープが必要な場合。 – VMAtm

    関連する問題