Соединение с SQL не закрывается после обращения к БД в ASP.NET

Asked
Viewd4357

0

У меня есть общий метод для вызова хранимой процедуры в ASP.NET:

 public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP)
        {
            SqlDataReader iReader;
            SqlCommand sql = new SqlCommand();

            sql.CommandText = sprocName;
            sql.CommandType = CommandType.StoredProcedure;
            sql.Connection = ConnStr;
            if (SqlP != null)
            {
                foreach (SqlParameter p in SqlP)
                {
                    sql.Parameters.Add(p);
                }

            }
            sql.Connection.Open();
            iReader = sql.ExecuteReader(CommandBehavior.CloseConnection);
            sql.Dispose();

            return iReader;
        }
 

Хотя я вызываю CommandBehavior.CloseConnection, соединение не закрывается. Я могу получить данные при первом запросе страницы. При перезагрузке появляется следующая ошибка:

Соединение не было закрыто. В текущее состояние соединения открыто. Описание: необработанное исключение произошло во время выполнения текущий веб-запрос. Пожалуйста, просмотрите трассировка стека для получения дополнительной информации о ошибка и откуда она возникла код.

Сведения об исключении: System.InvalidOperationException: The соединение не было закрыто. В текущее состояние соединения открыто.

Ошибка источника:

Строка 35: Строка 36:} Строка 37: sql.Connection.Open (); Строка 38: iReader = sql.ExecuteReader (CommandBehavior.CloseConnection); Строка 39: sql.Dispose ();

Наконец, если я поставлю sql.Connection.Close (); перед sql.Dispose (); Я получаю сообщение об ошибке, что iReader не читается, потому что он уже закрыт.

Очевидно, я неправильно закрываю свое соединение, может ли кто-нибудь указать мне правильное направление?

4 ответов

4

Когда вы возвращаете DataReader, базовое соединение должно оставаться открытым. Ответственность за надлежащую очистку ресурсов лежит на потребителе.

 public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP)
{
    SqlCommand sql = new SqlCommand();

    sql.CommandText = sprocName;
    sql.CommandType = CommandType.StoredProcedure;
    sql.Connection = ConnStr;
    if (SqlP != null)
    {
        foreach (SqlParameter p in SqlP)
        {
            sql.Parameters.Add(p);
        }

    }
    sql.Connection.Open();
    return sql.ExecuteReader(CommandBehavior.CloseConnection);          
}

public void ConsumingMethod()
{
    using(SqlDataReader reader = ExecuteStoredProc("MyProc", params))
    {
        while(reader.Read())
        {
            //work with your reader
        }
    }
}
 
  • Разве вам не нужно закрывать и удалять соединение, которое вы создаете в ExecuteStoredProc?

    Roman Starkov18 февраля 2010, 19:23
  • Я согласен с вашим подходом «ответственность потребителя за надлежащую очистку ресурсов», но, как правило, на это не следует полагаться, потребитель слишком ленив для этого.

    J.W.03 июня 2009, 20:16
  • Спасибо, это помогло. Я добавил iReader.Close () к моему методу потребления после цикла while.

    RedWolves03 июня 2009, 20:16
  • @romkyns: Поскольку Reader был создан с CommandBehavior.CloseConnection, соединение будет закрыто, когда ConsumingMethod Читатель закрывается с помощью оператора using: http://msdn.microsoft.com/en-us/library/system.data.commandbehavior%28VS.80%29.aspx. Это кажется опасным, поскольку мы должны доверять потребителю, чтобы он поступал правильно, но это единственное решение, если Reader покидает область действия метода.

    Corbin March18 февраля 2010, 20:31
1

Я бы посоветовал обернуть соединение sql оператором using, и это решит большинство проблем с соединением sql.

 using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
 

}

  • Кроме того, я не предлагаю возвращать SqlDataReader, лучше всего инициализировать пользовательский объект, а затем вернуть его.

    J.W.03 июня 2009, 20:14
0

Идея состоит в том, чтобы выполнить Connection.Close (); после того, как вы закончили с SqlReader, поэтому в основном вместо того, чтобы помещать оператор close () перед командой SqlReader.Dispose (), вы должны поместить его ниже.

0

Это мой предпочтительный способ обработки IDataReader. Позвольте вызывающему объекту создать экземпляр SqlConnection и передать его методам.

Создание экземпляра SqlConnection - дорогое удовольствие. И вы закончите тем, что код вызовет один и тот же метод ExecuteStoredProc несколько раз в разных ситуациях.

Таким образом, я реорганизовал метод ExecuteStoredProc, добавив экземпляр SqlConnection как часть параметра.

 using (SqlConnection conn = new SqlConnection())
{
    conn.ConnectionString = // Connection String;
    conn.Open();

    using (IDataReader reader = foo.ExecuteStoredProc(conn, sprocName, SqlP))
    {
        // Process IDataReader
    }
}