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

C# : there is already an open DataReader associated with this command

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

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

There is already an open DataReader associated with this Command which must be closed first

所以我用谷歌搜索了一下,读到

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;
        }
    }
}

谢谢!

如错误消息所示,您已经有一个打开的 DataReader 与该 Command 对象相关联。

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

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

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

外部和内部命令使用不同的命令实例;所以基本上:

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

(每个命令都类似)

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