web-dev-qa-db-ja.com

Entity Frameworkでトランザクションを使用するにはどうすればよいですか?

次のようなコードがある場合:

Something something = new Something();
BlahEntities b = new BlahEntities()    
b.AddToSomethingSet(something);
b.SaveChanges();

トランザクション内でその追加をどのように実行しますか?

27
pupeno

コードをTransactionスコープ内に配置できます

using(TransactionScope scope = new TransactionScope())
{
    // Your code
    scope.Complete(); //  To commit.
}

TransactionScopeは、同じ名前のアセンブリにあるSystem.Transactions名前空間にあります(プロジェクトに手動で追加する必要がある場合があります)。

26
Shiraz Bhaiji

ObjectContextには、トランザクションの管理に使用できる接続プロパティがあります。

using (var context = new BlahEntities())
using (var tx = context.BeginTransaction())
{
    // do db stuff here...
    tx.Commit();
}

例外が発生した場合、トランザクションはロールバックされます。 BeginTransaction()の呼び出しには接続が必要であり、接続を開くため、BeginTransactionの呼び出しを拡張メソッドでラップすることは理にかなっています。

public static DbTransaction BeginTransaction(this ObjectContext context)
{
    if (context.Connection.State != ConnectionState.Open)
    {
        context.Connection.Open();
    }
    return context.Connection.BeginTransaction();
}

このアプローチがTransactionScopeよりも有用であると私が考える1つのシナリオは、2つのデータソースにアクセスする必要があり、接続の1つでトランザクション制御のみが必要な場合です。その場合、TransactionScopeは、要求されない可能性のある分散トランザクションに昇格すると思います。

55
Kim Major

LINQ to SQLでは、既存のアンビエントトランザクションがない場合(TransactionScopeは「アンビエント」トランザクション)、データコンテキストがSubmitChanges()のトランザクションを作成することを知っています。 LINQ to Entitiesでこれが文書化されているのを見たことはありませんが、Entity Frameworkにも当てはまることを示唆する動作を見てきました。

したがって、関連するすべての変更に1つのSubmitChanges()(L2SQL)またはSaveChanges()(Linq to Entities)を使用している限り、TransactionScopeを使用しなくても問題ありません。 TransactionScopeが必要な場合

  1. 1つのトランザクションで複数のSubmitChanges/SaveChangesを使用して複数の変更を保存する。
  2. 1つのトランザクション内で複数のデータソースを更新する(LinqやASP.NETメンバーシップSQLプロバイダーなど)。
  3. 独自の更新を行う可能性のある他のメソッドを呼び出す。

ネストされたTransactionScopesで問題が発生しました。それらは機能するはずであり、簡単なテストケースは機能しますが、実稼働コードに入ると、「内部」トランザクションは外部トランザクションと同じオブジェクトのようです。症状には、「トランザクションがコミットされました。このトランザクションを使用できなくなりました」または「このトランザクションオブジェクトはすでに破棄されています」などのエラーが含まれます。エラーは、内部トランザクションが処理を行った後に、外部トランザクションで発生します。

9
Cylon Cat
using System.Transactions;

using (TransactionScope scope = new TransactionScope())
{
    try
    {
        using(DataContext contextObject = new DataContext(ConnectionString))
        {
            contextObject.Connection.Open();
            // First SaveChange method.
            contextObject.SaveChanges();

            // Second SaveChange method.
            contextObject.SaveChanges();
            //--continue to nth save changes

            // If all execution successful
            scope.Complete();   
       }
    }
    catch(Exception ex)
    {
        // If any exception is caught, roll back the entire transaction and end the scope.
        scope.Dispose();
    }
    finally
    {
        // Close the opened connection
        if (contextObject.Connection.State == ConnectionState.Open)
        {
            contextObject.Connection.Close();
        }
    }
}

詳細な説明については、以下のリンクを参照してください https://msdn.Microsoft.com/en-us/data/dn456843.aspx

1

Entity Frameworkのすべてのバージョンで、SaveChanges()を実行してデータベースで挿入、更新、または削除を行うと、フレームワークはその操作をトランザクションでラップします。このトランザクションは、操作を実行するのに十分なだけ長く続き、その後完了します。そのような別の操作を実行すると、新しいトランザクションが開始されます。 Entity Frameworkの最新バージョン:6.0以降

詳細はこちら: EntityFramework and Transaction

0
Mesut Talebi2