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);
}
Объект соединения, являющийся свойством объекта команды, делает использование блока неудобным в этой ситуации - но этот шаблон выполняет работу, не загромождая ваш код.