我有一个外部库,我将System.Data.SqlClient.SqlConnection
的实例传递给该外部库,并且我想将该库在该连接中进行的所有操作包装在事务中。当我使用php / doctrine时,在这种情况下,我会完全做到这一点-在我的代码中启动事务,在库中调用发出DB查询的内容,然后在我的代码中提交事务。当我尝试在C#中使用这种方法时,出现以下异常:
ExecuteScalar要求分配给命令的连接处于挂起的本地事务中时,该命令必须具有事务。该命令的Transaction属性尚未初始化。
因此,我看了一下库代码,它始终使用SqlCommand
而不设置Transaction
属性。是否可以通过某种方式实现我的目标? (更改库代码是不可行的)
答案 0 :(得分:1)
您尚未发布代码,但我认为您尝试通过调用SqlConnection.BeginTransaction()
来使用显式事务。
您可以使用TransactionScope创建隐式事务。在TransactionScope生存期内创建的任何连接命令都将自动加入事务中。
从Implementing an Implicit Transaction using Transaction Scope的示例复制:
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
此示例中的连接和两个命令都在单个事务下运行。如果发生异常,则事务将回滚。
答案 1 :(得分:0)
在.NET中,您可以使用TransationScope,所有操作都将在同一事务中发生:
using (TransactionScope scope = new TransactionScope())
{
// Everything inside this block will be transactional:
// Call the libraries which will use your SqlConnection here
}
或者您可以在调用其他库函数之前使用BeginTransaction,并在函数调用之后提交它