如果完成,ORMLite下的SQLite不允许在事务之后执行任何操作

时间:2013-03-20 17:28:49

标签: c# sqlite servicestack ormlite-servicestack

在我通过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的that line左右失败。但是,我根本不应该参与交易。

当我使用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中的错误吗?

2 个答案:

答案 0 :(得分:7)

在我目前正在使用的版本中,已经出现类似的问题reportedfixed。在将我的测试与the passing one进行比较后,我发现我没有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>());
            }
        }

答案 1 :(得分: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 (var db = DatabaseFactory.OpenDbConnection()) {
    using (var transaction = db.BeginTransaction(IsolationLevel.ReadCommitted)) {
        // do stuff here
    }
}

仍然,在调用service.Delete之后,第一行上抛出了“Transaction与命令连接无关”的异常。

我第一次尝试解决它(没有用)是这样的:

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

为什么这个解决方法有效,我仍然很模糊,但我想我会把它记录在其他人身上。