【问题标题】:ServiceStack Ormlite transactions broken?ServiceStack Ormlite 事务中断?
【发布时间】:2014-11-25 19:38:40
【问题描述】:

我正在为 SQL Server 使用 ServiceStack.Ormlite,并且刚刚从 3.9.71 更新到 4.0.33.0,现在直接命令的事务失败。我可以让 ORMlite 事务正常工作或直接命令,但不能两者兼而有之。

复杂之处在于我正在执行一些非常复杂的 DB 命令,并且由于用于大量 GUID 的 Sql.In() 非常慢,所以我有一个解决方法,它使用 db.CreateCommand() 然后将 GUID 列表作为自定义表格类型。

因此,我需要一个事务来跨越 ORMLite 命令和直接 db 命令。以下代码以前可以工作,现在失败了。

例如,以下代码曾经可以工作。我现在收到错误说 CreateCommand() 应该使用事务。当我直接尝试时,我会得到指示的cast exception

            using (var db = DB.Connection.OpenDbConnection())
            {
                using (var transaction = db.OpenTransaction())
                {
                    // Some ORMLite code
                    db.Delete<SomeType>();

                    using (var command = db.CreateCommand())
                    {
                        // Direct DB command
                        command.CommandText = "Delete from SomeTable where ...";
                        command.Parameters.Add(GUIDList)

                        command.ExecuteNonQuery();
                    }
                }
            }

说明: 在代码中 OpenTransaction() 将适用于 OrmLite 代码,但在 CreateCommand 代码上失败。 OrmLite 代码的 BeginTransaction() 将失败。

实际错误在 command.ExecuteNonQuery():当分配给命令的连接处于挂起的本地事务中时,ExecuteNonQuery 要求命令具有事务。该命令的 Transaction 属性尚未初始化。

【问题讨论】:

    标签: sql-server transactions ormlite-servicestack


    【解决方案1】:

    要使用Transactions in OrmLite,您应该使用OpenTransaction() API,例如:

    using (var trans = db.OpenTransaction()) 
    {
        //...
    }
    

    我添加了几个新 API,以便能够将 OrmLite 事务与原始 ADO.NET IDbCommand in this commit 一起使用。

    使用托管 OrmLite DB 命令

    使用带有OpenCommand() 的托管 OrmLite 命令,它将自动使用当前事务预填充 DB 命令,例如:

    using (var trans = db.OpenTransaction()) 
    using (var command = db.OpenCommand())
    {
        command.CommandText = "Delete from SomeTable where ...";
    }
    

    手动分配底层数据库事务

    使用底层 ADO.NET IDbCommand 时,您还需要自己手动将事务分配给命令,即:

    using (var trans = db.OpenTransaction()) 
    using (var command = db.CreateCommand())
    {
        command.Transaction = trans.ToDbTransaction();
        command.CommandText = "Delete from SomeTable where ...";
    }
    

    ToDbTransaction() 扩展方法允许您访问底层 ADO.NET IDbTransaction,这是使用底层 ADO.NET IDbCommand 时所必需的。

    这两个新 API 都可以从 v4.0.34+ 获得,现在是 available on MyGet

    【讨论】:

    • 我添加了一个说明。我实际使用的代码确实使用了适用于 OrmLite 的 OpenTransaction,但在 ADO.Net 代码上失败了。对于 OrmLite,BeginTransaction 将失败,但适用于 ADO.net 代码。
    【解决方案2】:

    这是我的建议。它基于以前的答案

    IDbConnection conn = DB.Connection;
    IDbCommand cmd = conn.CreateCommand();
    using (IDbTransaction transaction = conn.OpenTransaction())
    {
        //ADO.NET code
        cmd.Transaction = transaction.ToDbTransaction();
        cmd.CommandText = "...Some sql text";
        cmd.executeNonQuery();
        // Some ORMLite code
        conn.Delete<SomeType>();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 2013-01-19
      相关资源
      最近更新 更多