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 的那一行失败。但是,我根本不应该参与交易。

当我使用 SQL Server 作为提供程序时,代码如下

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));
    }
}

最终起作用的是在事务中的服务调用之后包装数据库调用。

[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 回答