none
LINQ to Entities + ADO.NET 2.0 Provider for SQLite + System.Transactions.TransactionScopeでエラー RRS feed

  • 質問

  • VS 2008 SP1 + .NET Framework 3.5 SP1でC#使用。

    マルチスレッド環境でSQLite3に安全に書き込みをする必要があったので、TransactionScopeを使おうと思いました。

    Microsoftの方の資料の22ページ目にあったサンプルを参考にやってみたんですが、
    http://download.microsoft.com/download/3/E/9/3E9E7EE6-CBCE-47E0-89F0-EB732C52037C/T3-304.pptx

    このようなエラーが出てしまいました。
    http://72qnsw.blu.livefilestore.com/y1pJOgl9oxxCLBgVdQYgZoxzJgX0TQPVpQ4pqMXAulIMuw_Ta5gtqkM5Ts8K981bAxBpNnirDmgEyY08wUQdP8maWW1ompiH6zt/SQLiteEntitiesAndTransactionScopeProblem.png

    想像するに、ObjectContextとTransactionScopeの両方がロックを掛けようとしているのではないかと思いました。

    ObjectContextを広域変数に入れておいて再利用できるようにしたい場合、トランザクションによるロールバックの仕組みを使えなければ、自分でlockしておいて、例外が発生したらAddToXXXなどしていたものをDeleteObjectしたりしないといけないので、なんというか、非常に原始的です。

    今のところはデータが必要なときに毎回ObjectContextを作り、例外が発生しないときだけSaveChange()し、終わったら毎回破棄しています。

    その方法だと以下の問題があります。
    (1) ObjectContextの生成と破棄は数十msかかるので、頻繁に呼び出すと処理が遅くなる。
    (2) 毎回破棄するのではDataGridViewなどのデータソースとして使用できない。

    ということで、やはりトランザクションを使うことができたほうがよいと思うのですが、なにか方法はありませんか?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Transactions;
    
    namespace SQLiteEntitiesAndTransactionScope
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (RoomUserEntities entities = new RoomUserEntities())
                {
                    using (TransactionScope transaction = new TransactionScope())
                    {
                        Room room = entities.Room.First();
                        Console.WriteLine("Initial RoomCardNumber={0}", room.card_no);
                        room.card_no = "1234567890123456";
                        Console.WriteLine("Modified RoomCardNumber={0}", room.card_no);
                        entities.SaveChanges(false);
                        transaction.Complete();
                    }
                    entities.AcceptAllChanges();
                }
            }
        }
    }
    • 編集済み yyamasak 2009年6月11日 3:34
    2009年6月11日 2:30

すべての返信

  • 確認ですが、MSDTC(Distributed Transaction Coordinator)サービスは起動されていますか?
    TransactionScopeクラスを使用したトランザクション処理にはこのサービスが必要です。
    そう考えると、インプロセスで動作するSQLiteに対してアウトプロセス(?)でトランザクション管理というのはなんともオーバーヘッドが大きい気もします。

    書かれているコードはObject Services のトランザクションを管理する方法 と同等なので、あとはSystem.Data.SQLite(でしたっけ?)の問題かと思います。
    2009年6月11日 3:58
  • MSDTC(Distributed Transaction Coordinator)サービスのことは知りませんでしたが、確認してみると起動していました。

    TransactionScopeというのは比較的新しい仕組みのようですが、他にも同等のことを実現する仕組みはあるのでしょうか?

    >あとはSystem.Data.SQLite(でしたっけ?)の問題かと思います。
    System.Data.SQLiteのフォーラムでも聞いてみようと思います。

    2009年6月11日 12:43