Help us understand the problem. What is going on with this article?

[Entity Framework] トランザクションのスコープ制御(EF4.1~:Model/Database First)

Entity Framework のコンテキストにおいて、トランザクションは、既定では SaveChanges() を実行したときに暗黙的に使用されます。

要件によっては、トランザクションのスコープを明示的に制御したいケースも出てくるでしょう。
ここでは EF4.1 以降の DbContext を例に、その方法をご紹介します。

※EF6 では別の方式が推奨されるようになりました。「トランザクションのスコープ制御(EF6:Model/Database First)」をご参照ください。
※Code First 版はこちらの記事で公開しています。

複数回の SaveChanges をまたぐトランザクション

// コンテキスト
using (var context = new NorthwindEntities())
{
    // SaveChanges() を実行するたびに接続が開閉され、分散トランザクションになるのを防ぐため、あらかじめ開いておく。
    ((IObjectContextAdapter)context).ObjectContext.Connection.Open();

    // TransactionScope で囲む。
    var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
    using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
    {
        // 1つめの SaveChanges()
        var product = context.Products.Single(p => p.ProductID == 1);
        product.ProductName = "New Product Name";
        context.SaveChanges();

        // 2つめの SaveChanges()
        var employee = context.Employees.Single(e => e.EmployeeID == 1);
        employee.Title = "New Title";
        context.SaveChanges();

        // まとめてコミット
        scope.Complete();
    }
}

TransactionScope 内で例外が発生した場合は、トランザクションがロールバックされます。

※TransactionScope を使用するには、System.Transactions.dll を参照設定する必要があります。

複数のコンテキストをまたぐトランザクション

既存の接続をコンストラクタに指定してコンテキストを生成することによって、複数のコンテキスト間で接続やトランザクションを共用することができます。

// 共用する接続の作成
using (var connection = new EntityConnection("name=NorthwindEntities"))
{
    // SaveChanges() を実行するたびに接続が開閉され、分散トランザクションになるのを防ぐため、あらかじめ開いておく。
    connection.Open();

    // TransactionScope で囲む。
    var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
    using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
    {
        // 1つめのコンテキスト(接続を指定して生成)
        using (var context = new NorthwindEntities(connection, false))
        {
            var product = context.Products.Single(p => p.ProductID == 1);
            product.ProductName = "New Product Name";
            context.SaveChanges();
        }

        // 2つめのコンテキスト(接続を指定して生成)
        using (var context = new NorthwindEntities(connection, false))
        {
            var employee = context.Employees.Single(e => e.EmployeeID == 1);
            employee.Title = "New Title";
            context.SaveChanges();
        }

        // まとめてコミット
        scope.Complete();
    }
}

// コンテキストの部分クラス
public partial class NorthwindEntities : DbContext
{
    /// <summary>
    /// コンストラクタ。
    /// </summary>
    /// <param name="existingConnection">コンテキストで使用する接続。</param>
    /// <param name="contextOwnsConnection">false を指定すると、コンテキストが Dispose されたときに接続を Dispose しない。</param>
    public NorthwindEntities(DbConnection existingConnection, bool contextOwnsConnection)
        : base(existingConnection, contextOwnsConnection)
    {
    }
}

トランザクション直接操作

TransactionScope を使用せずに、DbTransaction オブジェクトを直接操作することも可能です。

using (var context = new NorthwindEntities())
{
    var connection = ((IObjectContextAdapter)context).ObjectContext.Connection;
    connection.Open();

    // トランザクション開始
    using (var transaction = connection.BeginTransaction())
    {
        try
        {
            var product = context.Products.Single(p => p.ProductID == 1);
            product.ProductName = "New Product Name";
            context.SaveChanges();

            var employee = context.Employees.Single(e => e.EmployeeID == 1);
            employee.Title = "New Title";
            context.SaveChanges();

            // コミット
            transaction.Commit();
        }
        catch
        {
            // ロールバック
            transaction.Rollback();
            throw;
        }
    }
}
CodeOne
【品質と生産性にこだわるシステム開発】 .NET(C#/VB.NET)専門・リモート開発歴10年。即日・1時間から頼める常駐しないエンジニア。確かな技術で開発チームを手堅くサポートいたします。
https://codeone.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした