C#:已经有一个与此命令关联的开放DataReader

时间:2017-01-31 12:00:15

标签: c# sql-server transactions sqldatareader

我目前在单个方法中遇到多个SqlDataReader和命令的问题。此方法应删除客户及其相关地址,网络,ipaddresses ......

当我执行代码时,出现错误

  

已经有一个与此命令关联的打开DataReader,必须先关闭

所以我用Google搜索了一下,然后读了

using(SqlDataReader....)

并将MultipleActiveResultSets=True添加到连接字符串应该有帮助。

我正在使用SQL Server 2014,我听说SQL Server 2005存在问题,所以这不应该是个问题。

但它仍然不起作用......

抛出异常
var addressId = (int)command.ExecuteScalar();

连接字符串:

Data Source=.\\DATABASE;Initial Catalog=customer;Persist Security Info=True;MultipleActiveResultSets=True;User ID=sa;Password=xxxxxxxx!

代码:

public static Boolean ExecuteDeleteCutomer(string customerId) {
    using (SqlConnection connection = new SqlConnection(new DatabaseConnection().ConnectionString)) {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;
        SqlDataReader locationReader;
        SqlDataReader networkReader;
        SqlDataReader ipaddressReader;

        // Start a local transaction to delete a customer and related table entries.
        transaction = connection.BeginTransaction("StartTransaction DeleteCustomer");

        // Must assign both transaction object and connection
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;

        try {
            //First get the locations of selected customer
            command.Parameters.AddWithValue("@customerId", customerId);
            command.CommandText =
                    "SELECT l_id from location where c_id = @customerId";
            locationReader = command.ExecuteReader();

            using (locationReader) { //save location ids in a reader
                while (locationReader.Read()) {
                    var locationID = locationReader.NextResult();
                    command.Parameters.AddWithValue("@locationId", locationID);
                    command.CommandText =
                        "SELECT a_id from address where l_location = @locationId";
                    var addressId = (int)command.ExecuteScalar(); // get address ID to delete later

                    command.Parameters.AddWithValue("@addressId", addressId);
                    command.CommandText = "SELECT n_id from network where n_location = @locationId";

                    using (networkReader = command.ExecuteReader()) { // save networks in a reader;
                        while (networkReader.Read()) {
                            var networkId = networkReader.NextResult();
                            command.Parameters.AddWithValue("@networkId", networkId);
                            command.CommandText = "SELECT ip_id from ipaddress where n_id = @networkId";

                            using (ipaddressReader = command.ExecuteReader()) { // get ipaddressId ID to delete later
                                while (ipaddressReader.Read()) {
                                    var ipaddressId = ipaddressReader.NextResult();
                                    command.Parameters.AddWithValue("@ipId", ipaddressId);
                                    command.CommandText = "Delete from ipaddress where ip_id = @ipId; ";
                                    command.ExecuteScalar();
                                }
                            }

                            command.CommandText = "Delete from network where n_id = @networkId; ";
                            command.ExecuteScalar();
                        }
                    }

                    command.CommandText = "Delete from location where l_id = @locationID; ";
                    command.ExecuteScalar();
                }
            }

            command.CommandText = "Delete from customer where c_id = @customerId; ";
            command.ExecuteScalar();

            // Attempt to commit the transaction.
            transaction.Commit();

            return true;
        } 
        catch (Exception ex) {
            Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
            Console.WriteLine("  Message: {0}", ex.Message);

            // Attempt to roll back the transaction.
            try {
                transaction.Rollback();
            } 
            catch (Exception ex2) {
                // This catch block will handle any errors that may have occurred
                // on the server that would cause the rollback to fail, such as
                // a closed connection.
                Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
                Console.WriteLine("  Message: {0}", ex2.Message);
            }

            return false;
        }
    }
}

谢谢!

2 个答案:

答案 0 :(得分:1)

当错误消息显示时,您已经与该DataReader对象关联了一个打开的Command

您需要为要执行的每个(嵌套)命令创建一个新的SqlCommand对象。

SqlCommand locationCommand = connection.CreateCommand();
SqlCommand networkCommand = connection.CreateCommand();
SqlCommand ipAddrCommand = connection.CreateCommand();

根据需要为每个命令对象分配CommandText,然后您可以在每个命令对象上调用ExecuteReader并根据需要进行处理。

答案 1 :(得分:0)

对外部和内部命令使用不同的命令实例;基本上是这样的:

var innerCommand = ...
innerCommand.CommandText = "Delete from ipaddress where ip_id = @ipId; ";
var ipId = innerCommand.Parameters.Add(...);
while (ipaddressReader.Read()) {
    ipId.Value = ...
    innerCommand.ExecuteNonQuery();
}

(每个命令类似)

基本上,每个命令实例应该一次只执行一次,无论它们是否共享连接。

相关问题