代码之家  ›  专栏  ›  技术社区  ›  kojo

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

  •  5
  • kojo  · 技术社区  · 12 年前

    在我通过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; }}
    

    我得到的异常是:“事务与命令的连接不关联” that line 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中的一个错误吗?

    2 回复  |  直到 12 年前
        1
  •  7
  •   mythz    12 年前

    事实证明,类似的问题已经出现了 reported fixed 在我当前使用的版本中。在将我的测试与 the passing one 我发现我无法处理我的交易。

    最终的答案是: 必须处理该事务 。如果不是,则在使用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>());
                }
            }
    
        2
  •  2
  •   Matt Welch    11 年前

    我的问题类似,我的搜索结果是这样的。试图编写一个单元测试来测试我的服务,我得到了相同的“事务与命令的连接不关联”异常。与我的情况不同的是,我使用的唯一事务(在我测试的服务中)是正确处理它的连接,所以我认为这并不适用。

    (我使用的是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后的第一行还是引发了“事务与命令的连接不关联”异常。

    我第一次尝试解决这个问题(但没有成功)是这样的:

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

    我仍然不清楚为什么这种变通方法有效,但我想我会为其他遇到这种情况的人记录下来。