SqlCommand.Dispose закрывает соединение?

Могу ли я использовать этот подход эффективно?

using(SqlCommand cmd = new SqlCommand("GetSomething", new SqlConnection(Config.ConnectionString))
{
    cmd.Connection.Open();
    // set up parameters and CommandType to StoredProcedure etc. etc.
    cmd.ExecuteNonQuery();
}

Моя проблема заключается в следующем: закроет ли метод Dispose SqlCommand (который вызывается при выходе из блока using) базовый объект SqlConnection или нет?

3 ответа

Решение

Нет, избавление от SqlCommand не повлияет на соединение. Лучшим подходом было бы также обернуть SqlConnection в блоке использования:

using (SqlConnection conn = new SqlConnection(connstring))
{
    conn.Open();
    using (SqlCommand cmd = new SqlCommand(cmdstring, conn))
    {
        cmd.ExecuteNonQuery();
    }
}

Иначе, Соединение не изменяется тем фактом, что Команда, которая использовала это, была удалена (возможно, это то, что вы хотите?). Но имейте в виду, что Соединение также должно быть удалено, и, вероятно, более важно избавиться, чем команда.

РЕДАКТИРОВАТЬ:

Я только что проверил это:

SqlConnection conn = new SqlConnection(connstring);
conn.Open();

using (SqlCommand cmd = new SqlCommand("select field from table where fieldid = 1", conn))
{
    Console.WriteLine(cmd.ExecuteScalar().ToString());
}

using (SqlCommand cmd = new SqlCommand("select field from table where fieldid = 2", conn))
{
    Console.WriteLine(cmd.ExecuteScalar().ToString());
}

conn.Dispose();  

Первая команда была удалена при выходе из блока использования. Соединение было все еще открыто и хорошо для второй команды.

Таким образом, удаление команды определенно не избавляет от соединения, которое она использовала.

SqlCommand.Dispose не будет достаточным, поскольку многие SqlCommand(s) могут (повторно) использовать один и тот же SqlConnection. Сосредоточьте свое внимание на SqlConnection.

Так много мест ошибаются, даже собственная документация MS. Просто помните - в мире БД почти все поддерживается неуправляемым ресурсом, поэтому почти все реализует IDisposable. Предположим, что класс работает, если компилятор не говорит вам иначе. Оберните вашу команду в using. Оберните ваше соединение в using. Создайте соединение с помощью DbProvider (получите его от DbProviderFactories.GetFactory) и свою команду от вашего соединения, чтобы при изменении базовой БД вам нужно было только изменить вызов DBPF.GetFactory. Таким образом, ваш код должен выглядеть красиво и симметрично:

var provider = DbProviderFactories.GetFactory("System.Data.SqlClient");// Or MS.Data.SqlClient
using (var connection = provider.CreateConnection())
{
    connection.ConnectionString = "...";
    using (var command = connection.CreateCommand())
    {
        command.CommandText = "...";
        connection.Open();

        using (var reader = command.ExecuteReader())
        {
...
        }
    }
}

Я использую этот шаблон. У меня есть этот частный метод где-то в моем приложении:

private void DisposeCommand(SqlCommand cmd)
{
    try
    {
        if (cmd != null)
        {
            if (cmd.Connection != null)
            {
                cmd.Connection.Close();
                cmd.Connection.Dispose();
            }
            cmd.Dispose();
        }
    }
    catch { } //don't blow up
}

Затем я всегда создаю команды SQL и соединения в блоке try (но без переноса в блок using) и всегда получаю блок finally:

    finally
    {
        DisposeCommand(cmd);
    }

Объект соединения, являющийся свойством объекта команды, делает использование блока неудобным в этой ситуации - но этот шаблон выполняет работу, не загромождая ваш код.

Другие вопросы по тегам