5

ServiceStackのOrmLiteを介してSQLiteでトランザクションを作成してコミットした後、続行してクエリを発行することはできません。

たとえば、次のテストは失敗します。

        [Test, Explicit]
        public void Can_query_after_transaction_is_committed()
        {
            var connection = new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider, true);
            using (var db = connection.OpenDbConnection())
            {
                db.DropAndCreateTable<SimpleObject>();
                var trans = db.OpenTransaction();
                db.Insert(new SimpleObject{test="test"});
                trans.Commit();
                Assert.DoesNotThrow(()=> db.Select<SimpleObject>()); //throws
            }
        }

class SimpleObject{public string test { get; set; }}

私が得る例外は、「トランザクションはコマンドの接続に関連付けられていません」というもので、OrmLiteのその行で失敗します。しかし、私はその取引に一切関与すべきではありません。

次のようなコードでSQLServerをプロバイダーとして使用する場合

new OrmLiteConnectionFactory(
                    @"Data Source=.\SQLEXPRESS;Initial Catalog=TestEmpty;Persist Security Info=True;User ID=db;Password=db;",
                     false, SqlServerDialect.Provider, true);*/

このテストは正常に機能します。

トランザクションを誤って終了していますか?ServiceStack.OrmLiteのバグですか?

4

2 に答える 2

7

私が現在使用しているバージョンでも、同様の問題がすでに報告され、修正されていることがわかりました。私のテストを合格したテストと比較した後、私は自分のトランザクションをDispose()しなかったことがわかりました。

結局のところ、答えは次のとおりです。トランザクションを破棄する必要があります。そうでない場合、SQLiteを使用するときにコードが失敗します。

次のテストに合格します。

        public void Can_query_after_transaction_is_committed()
        {
            var connection = new OrmLiteConnectionFactory(":memory:", true, SqliteDialect.Provider, true);
            using (var db = connection.OpenDbConnection())
            {
                db.DropAndCreateTable<SimpleObject>();
                using (var trans = db.OpenTransaction()) 
                {
                   db.Insert(new SimpleObject {test = "test"});
                   trans.Commit();
                }
                Assert.DoesNotThrow(()=> db.Select<SimpleObject>());
            }
        }
于 2013-03-21T10:05:06.060 に答える
2

私の問題も同様で、私の検索はここにつながりました。サービスをテストするために単体テストを作成しようとすると、同じ「トランザクションがコマンドの接続に関連付けられていません」という例外が発生していました。私の状況の違いは、(テストしていたサービスで)使用していた唯一のトランザクションが接続を正しく処理していたため、これが適用されるとは思わなかったということです。

(私はServiceStack v3.9.71を使用しています。)

私のテストコード(失敗しました)は次のようになりました:

[Test]
public void Test_Service_Delete() {
    var DatabaseFactory = new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider, true);

    using (var db = DatabaseFactory.OpenDbConnection()) {
        var parentId = db.InsertParam(new ParentObject { name = "Bob" }, true);
        db.Insert(new ChildObject { ParentId = parentId, name = "Sam" });

        var service = Container.Resolve<TestService>();
        var response = service.Delete(new DeleteRequestObject(parentId));

        Assert.That(db.Select<ParentObject>(parentId), Has.Count.EqualTo(0));
        Assert.That(db.Select<ChildObject>("ParentId = {0}", parentId), Has.Count.EqualTo(0));
    }
}

私のTestService.Deleteメソッドにはトランザクションが含まれていましたが(オブジェクトと関連する子オブジェクトを削除するため)、次のようにusingブロックにラップされていました。

using (var db = DatabaseFactory.OpenDbConnection()) {
    using (var transaction = db.BeginTransaction(IsolationLevel.ReadCommitted)) {
        // do stuff here
    }
}

それでも、service.Deleteの呼び出し後、最初の行で「トランザクションはコマンドの接続に関連付けられていません」という例外がスローされました。

それを解決するための私の最初の試み(これは機能しませんでした)はこれでした:

[Test]
public void Test_Service_Delete() {
    var DatabaseFactory = new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider, true);

    int parentId;
    using (var db = DatabaseFactory.OpenDbConnection()) {
        parentId = db.InsertParam(new ParentObject { name = "Bob" }, true);
        db.Insert(new ChildObject { ParentId = parentId, name = "Sam" });
    }

    var service = Container.Resolve<TestService>();
    var response = service.Delete(new DeleteRequestObject(parentId));

    using (var db = DatabaseFactory.OpenDbConnection()) {    
        Assert.That(db.Select<ParentObject>(parentId), Has.Count.EqualTo(0));
        Assert.That(db.Select<ChildObject>("ParentId = {0}", parentId), Has.Count.EqualTo(0));
    }
}

最終的に機能したのは、トランザクションでのサービス呼び出しの後にdb呼び出しをラップすることでした。

[Test]
public void Test_Service_Delete() {
    var DatabaseFactory = new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider, true);

    int parentId;
    using (var db = DatabaseFactory.OpenDbConnection()) {
        parentId = db.InsertParam(new ParentObject { name = "Bob" }, true);
        db.Insert(new ChildObject { ParentId = parentId, name = "Sam" });
    }

    var service = Container.Resolve<TestService>();
    var response = service.Delete(new DeleteRequestObject(parentId));

    using (var db = DatabaseFactory.OpenDbConnection()) {
        using (var transaction = db.OpenTransaction()) {
            Assert.That(db.Select<ParentObject>(parentId), Has.Count.EqualTo(0));
            Assert.That(db.Select<ChildObject>("ParentId = {0}", parentId), Has.Count.EqualTo(0));
        }
    }
}

この回避策が機能する理由についてはまだあいまいですが、これに遭遇した他の人のために文書化すると思いました。

于 2014-04-04T16:07:28.540 に答える