我正在使用ServiceStack.Ormlite for SQL Server,刚刚从3.9.71更新到4.0.33.0,现在直接命令的事务失败了。我可以让ORMlite事务工作或直接命令,但不能同时使用。
复杂的是我正在做一些非常复杂的数据库命令,并且由于Sql.In()对于大量的GUID列表非常慢,我有一个使用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属性尚未初始化。
答案 0 :(得分:1)
要使用Transactions in OrmLite,您应该使用OpenTransaction()
API,例如:
using (var trans = db.OpenTransaction())
{
//...
}
我已经添加了一些新的API,以便能够将OrmLite事务与原始ADO.NET IDbCommand
in this commit一起使用。
使用带有OpenCommand()
的托管OrmLite命令,该命令将自动使用当前事务预填充DB命令,例如:
using (var trans = db.OpenTransaction())
using (var command = db.OpenCommand())
{
command.CommandText = "Delete from SomeTable where ...";
}
使用底层ADO.NET IDbCommand
时,您还需要自己手动将Transaction分配给命令,即:
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。
答案 1 :(得分:0)
这是我的建议,有效。它基于以前的答案
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>();
}