Ключевое слово using
только вызывает метод .Dispose()
. Если у вас есть необходимый очистка, которая происходит вне метода dispose для объекта IDisposable, то вам нужно будет сделать это в своем собственном блоке finally. Это поднимает два пункта:
- В этот момент вы можете утверждать, что вы можете также пропустить блок using и просто вызвать Dispose () внутри блока finally. Лично я бы все-таки пошел с блоком
using
. Это просто хорошая привычка быть в всегда , чтобы иметь его для ваших IDisposable экземпляров.
- Я смиренно предлагаю, чтобы, если вы соблюдаете вышеизложенные условия, вам необходимо изменить дизайн своего класса, чтобы воспользоваться преимуществом шаблона IDisposable.
Судя по опубликованному вами коду, проблема в том, что ваши параметры все еще где-то укоренены (возможно, вы их повторно используете?). Поскольку параметры все еще укоренены, они не могут быть собраны. Они также содержат ссылку на команду, к которой они присоединены, поэтому ваш объект SqlCommand также не может быть собран сразу, потому что теперь он все еще укоренен.
Ключевым моментом является то, что .Net Framework резервирует шаблон Dispose () для неуправляемых ресурсов. Поскольку SqlParameters и SqlParameterCollection являются управляемыми типами, они не затрагиваются до тех пор, пока не будут собраны, что происходит совершенно отдельно от утилизации. Когда ваша SqlCommand будет наконец собрана, о ее SqlParameter также будет позаботиться. Только не путайте сбор, утилизацию и их цели.
Что вы хотите сделать, это сделать копию каждого параметра при добавлении, а не добавлять существующий параметр в коллекцию.
public static DataTable GetDataTable(string cmdText, IEnumerable<Parameter> parameters)
{
// Create an empty memory table.
DataTable dataTable = new DataTable();
// Prepare a connection to the database and command to execute.
using (SqlConnection connection = new SqlConnection(ConfigurationTool.ConnectionString))
using (SqlCommand command = new SqlCommand(cmdText, connection))
{
command.CommandType = CommandType.StoredProcedure;
SqlParameterCollection parameterCollection = command.Parameters;
foreach (Parameter parameter in parameters)
parameterCollection.Add(CloneParameter(parameter.SqlParameter));
// Execute the stored procedure and retrieve the results in the table.
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
{
dataAdapter.Fill(dataTable);
}
}
return dataTable;
}
Некоторые вещи, на которые следует обратить внимание: я смог избавиться от всех ваших пробных блоков. Ни один из них не был нужен. Кроме того, метод SqlDataAdapter.Fill () откроет и закроет соединение для вас, поэтому вам не нужна эта часть.
Теперь поговорим об этой функции CloneParameter (). У меня сложилось впечатление, что вы чувствуете, что он побеждает цель вашего кода, а именно попытаться повторно использовать параметры. Я обещаю вам, что повторное использование параметра здесь - плохая идея. Потеря производительности незначительна до точки несуществования, особенно по сравнению с выполнением хранимой процедуры. Я оставил вам реализацию CloneParameter () по двум причинам: во-первых, это тривиально, а во-вторых, мы уже за пределами моей обычной схемы доступа к данным. Обычно я добавляю параметры, принимая делегат Action , а не перечисляемый параметр. Функция объявлена так:
public IEnumerable<IDataRecord>GetData(string cmdText, Action<SqlParameterCollection> addParameters)
и называется так:
foreach(var record in GetData("myprocedurename", p =>
{
p.Add( /*new parameter here*/ );
p.Add( /*new parameter here*/ );
//...
})
.Select( /*Returning a IEnumerable rather than a datatable allows me to use it with linq to objects.*/
/* For example, you could use this spot to convert from DataRecords returned by ADO.Net to business objects */
))
{
// use the results here...
}
Поскольку вы заполняете две таблицы подряд, похоже, у вас есть какая-то работа по выполнению клиентской части, которая может оправдать это по сравнению с подходом DataReader / IEnumerable, но я хочу упомянуть об этом, поскольку в большинстве случаев Ваш код на DataReader является лучшим вариантом.
То, что я бы сделал в вашем случае с моим существующим шаблоном на основе делегатов Action и желанием максимально использовать повторяющийся набор параметров, - это настоящий именованный метод, который знает, как добавлять параметры и совпадения делегат моего действия. Тогда я мог бы просто передать этот метод и получить нужный параметр для повторного использования.