DataReader уже открыт - PullRequest
1 голос
/ 21 января 2012

У меня проблема с ошибкой, которая говорит о том, что мой datareader уже открыт.

Мой код выглядит так

public static Users GetByID(int ID, SqlConnection connection)
    {
        SqlCommand command = new SqlCommand("Select Name, Email, LastLogin, FK_Role_ID from Users where ID=@id");
        command.Connection = connection;

        command.Parameters.Add(new SqlParameter("id", ID));

        SqlDataReader reader = command.ExecuteReader();
        if (reader.Read())
        {
            Users user = new Users();
            user.ID = ID;
            user.Name = reader.GetString(0);
            user.Email = reader.GetString(1);
            user.LastLogin = reader.GetString(2);
            user.role = Role.GetRoleByID(reader.GetInt32(3), connection);
            reader.Close();
            return user;
        }
        else
        {
            reader.Close();
            return null;
        }
    }

Ошибка возникает в Role.GetRoleByID, говорящем, что команда чтения данных открыта уже. Что верно, но как мне вызвать Role.GetRoleByID с информацией из моего читателя.

я кодирую в c # и ASP.NET

Ответы [ 3 ]

4 голосов
/ 21 января 2012

Похоже, что Role.GetRoleByID попытается повторно использовать соединение.

Параметры:

  • Получите нужные данные из SqlDataReader в GetByID, закройтеэтот читатель и затем вызов Role.GetRoleByID (так что у вас есть только один активный читатель за один раз)
  • Включить несколько активных наборов результатов (MARS) - я не могу сказать, что у менялюбой опыт этого
  • Заставьте каждый метод использовать отдельное соединение, чтобы уменьшить зависимости между методами.Обратите внимание, что пул соединений сделает открытие / закрытие достаточно дешевым.

Я бы выбрал первый вариант на вашем месте - или, возможно, последний.Я бы также использовал оператор using для автоматического закрытия читателя:

private const string GetUserByIdSql =
    "Select Name, Email, LastLogin, FK_Role_ID from Users where ID=@id";

public static Users GetByID(int ID, SqlConnection connection)
{
    var sql = ;
    Users user;
    int roleId;
    using (var command = new SqlCommand(GetUserByIdSql, connection))
    {
        command.Parameters.Add(new SqlParameter("id", ID));
        using (var reader = command.ExecuteReader())
        {
            if (!reader.Read())
            {
                return null;
            }
            user = new Users
            {
                Name = reader.GetString(0),
                Email = reader.GetString(1),
                LastLogin = reader.GetString(2),
            };
            // Remember this so we can call GetRoleByID after closing the reader
            roleID = reader.GetInt32(3);
        }
    }
    user.Role = Role.GetRoleByID(roleID, connection);
    return user;
}

В качестве четвертого варианта - почему бы просто не выполнить соединение, требуемое GetRoleByID в существующем запросе?Это означало бы, что вам потребуется только одна поездка в базу данных.

2 голосов
/ 21 января 2012

Вы можете рассмотреть возможность использования запроса Select с необходимым соединением, чтобы иметь возможность получать роли из того же запроса.

Также рекомендуется использовать (using reader = command.ExecuteReader() ), чтобы считыватель был закрыт и утилизирован, как только закончится область действия.

1 голос
/ 21 января 2012

Разрешили ли вы MARS строку подключения (MultipleActiveResultSets=true)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...