【问题标题】:Does an ADO.NET transaction need to be assigned to the command object when using Connection.CreateCommand()?使用 Connection.CreateCommand() 时是否需要将 ADO.NET 事务分配给命令对象?
【发布时间】:2012-12-14 01:34:57
【问题描述】:

我需要通过 ADO.NET 提供程序使用事务。

下面是一个正在创建的连接、事务和命令的简单示例。当我使用connection.CreateCommand() 创建命令时,是否需要将事务分配给命令?或者,是因为我使用connection.CreateCommand() 而不是更新命令对象而设置了事务?

var connection = Database.GetConnection();
connection.Open();

var transaction = connection.BeginTransaction();

var command = connection.CreateCommand();
command.Transaction = transaction; // Is this line needed when using connection.CreateCommand()?

*更新*

当我测试两个对象的引用时,它们是相同的。我假设这意味着connection.CreateCommand() 正在返回一个分配了事务的命令。或者这可能不是一个有效的测试。

using (var connection = Database.GetConnection())
{
    connection.Open();

    var transaction = connection.BeginTransaction();

    var command = connection.CreateCommand();

    if (object.ReferenceEquals(transaction, command.Transaction))
        Debug.WriteLine("EQUAL");
}

【问题讨论】:

标签: c# ado.net


【解决方案1】:

是的,事务和命令需要相互关联。

一些经过编辑的示例代码:

// Connect to the database.
SqlConnection connection = new SqlConnection(Database.ConnectionString);
connection.Open();

// Start a transaction.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.Transaction = connection.BeginTransaction(System.Data.IsolationLevel.Serializable, "ryan");

// Delete any previously associated targets.
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = "FirstSP";
command.Parameters.AddWithValue("@Id", this.Id);
command.ExecuteNonQuery();

// Add the specified targets to the product.
command.CommandText = "SecondSP";
command.Parameters.Add("@Id", SqlDbType.Int);
foreach (int Id in Ids)
{
    command.Parameters["@Id"].Value = Id;
    command.ExecuteNonQuery();
}

// Commit the transaction.
command.Transaction.Commit();

// Houseclean.
connection.Close();

【讨论】:

    【解决方案2】:

    您必须为每个SqlCommand 实例显式设置事务。 Here is the source code of System.Data.SqlClient.SqlConnection.cs (Line: 782)CreateCommand

    new public SqlCommand CreateCommand() {
        return new SqlCommand(null, this);
    }
    

    如你所见;它通过nullCommandTextthis(本身)为SqlConnection 参数。

    【讨论】:

      【解决方案3】:

      如果您使用TransactionScope,则无需将任何内容附加到命令对象。

      看看the example from the documentation of TransactionScope

      【讨论】:

      • TransactionScope 默认以可序列化模式运行事务,您需要将事务隔离级别设置为 Dirty Read 否则会遇到性能和表锁问题
      【解决方案4】:
      using (var connection = new SqlConnection(Database.ConnectionString))
      {
         connection.Open();
         using (var trans = connection.BeginTransaction())
         {
             using (var command = trans.Connection.CreateCommand())
             { 
                command.CommandText = 'DELETE FROM TABLE_NAME WHERE ID = ?'; 
                command.Transaction = trans;
                command.ExecuteNonQuery();
             }
             trans.Commit();
         }
      }
      

      【讨论】:

        【解决方案5】:

        如果您使用connection.CreateCommand,并且连接已经启动了事务,则生成的命令对象将被列入事务(将设置命令的事务属性)。

        如果您使用new Command,您必须明确设置事务。

        【讨论】:

        • 遗憾的是,您仍然必须明确设置事务。虽然不是很直观,Microsoft states this is by design。尽管查看SqlConnection.CreateCommand source 一样容易,但使用快速控制台应用程序确认这一点很简单。
        • 是的。在从 Oracle 11 迁移到 SQL Server 之后,我发现这是真的。使用 Oracle 驱动程序,您无需在命令上显式设置事务。 SQL Server 2012 并非如此!
        猜你喜欢
        • 2010-10-12
        • 1970-01-01
        • 2013-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多