Соединение закрывается только при удалении экземпляра класса DataBase
. Однако, хотя этот класс реализует одноразовый шаблон, он не реализует интерфейс IDisposable
- поэтому вы не можете использовать его в выражении using
.
Более того, вы должны полагаться на тех, кто использует этот класс, чтобы распоряжаться им.
Если они этого не сделают, соединение не будет закрыто, пока не будет вызван финализатор, и это полностью вне контроля разработчика. Он может даже не вызываться вообще - сборщику мусора может не потребоваться очистка памяти во время выполнения того приложения, которое использует этот код.
Вот почему правильный способ обработки соединений с базой данных - это локальная переменная внутри оператора using.
То, что вы хотите сделать, это создать соединение и открыть его как можно позже, и утилизировать его как можно скорее.
Правильный метод для обработки вызовов к базе данных выглядит следующим образом:
int ExecuteNonQuery(string sql)
{
using(var con = new SqlConnection(connectionString))
{
using(var cmd = new SqlCommand(sql, con))
{
con.Open();
return cmd.ExecueNonQuery();
}
}
}
Конечно, вы захотите добавить аргументы для хранения любых параметров, которые вам нужно передать в базу данных, и аргумент для хранения Тип команды, но это должно быть построено на основе этой структуры.
У меня есть проект на GitHub под названием ADONETHelper (которым я пренебрегал в течение последнего года или около того из-за нехватки свободного времени), который был написан для уменьшения повторения кода при использовании ADO .Net напрямую.
Я написал это несколько лет назад, поэтому, конечно, теперь я имею в виду улучшения, но, как я уже сказал, у меня нет свободного времени, чтобы поработать над этим - но общая идея по-прежнему актуальна и полезна. По сути, у него есть единственный метод Execute
, который выглядит следующим образом:
public T Execute(string sql, CommandType commandType, Func function, params IDbDataParameter[] parameters)
{
using (var con = new TConnection())
{
con.ConnectionString = _ConnectionString;
using (var cmd = new TCommand())
{
cmd.CommandText = sql;
cmd.Connection = con;
cmd.CommandType = commandType;
if (parameters.Length > 0)
{
cmd.Parameters.AddRange(parameters);
}
con.Open();
return function(cmd);
}
}
}
, чем я добавил несколько методов, которые используют этот метод:
public int ExecuteNonQuery(string sql, CommandType commandType, params IDbDataParameter[] parameters)
{
return Execute(sql, commandType, c => c.ExecuteNonQuery(), parameters);
}
public bool ExecuteReader(string sql, CommandType commandType, Func populate, params IDbDataParameter[] parameters)
{
return Execute(sql, commandType, c => populate(c.ExecuteReader()), parameters);
}
и так далее.
Не стесняйтесь заимствовать идеи из этого проекта - или даже использовать их как есть - у меня есть несколько приложений, использующих это, и они работают очень хорошо в течение довольно долгого времени.
Я думаю, что Accesschk может сделать это.
От командной строки: accesschk.exe -osv > objects.txt
Поиск: "Тип: раздел"