Рекомендации ADO.NET для области подключения и объекта DataAdaptor

Это мой первый пост на StackOverflow, так что будьте осторожны ...

У меня есть несколько вопросов относительно области объекта для ADO.NET.

Когда я подключаюсь к базе данных, я обычно использую такой код:

OleDbConnection conn = new OleDbConnection("my_connection_string");
conn.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * from Employees", conn);
OleDbCommandBuilder cb = new OleDbCommandBuilder(adapter);
DataTable dt = new DataTable();
adapter.Fill(dt);
conn.Close();
conn.Dispose();

Допустим, я привязываю полученный DataTable к элементу управления сеткой и разрешаю пользователям редактировать содержимое сетки. Теперь, когда мои пользователи нажимают кнопку «Сохранить», мне нужно вызвать этот код:

adapter.Update(dt);

Вот мои вопросы:

1) Нужно ли мне сохранять объект адаптера, который я создал при первоначальной загрузке таблицы данных, или я могу создать другой объект адаптера в событии нажатия кнопки «Сохранить» для выполнения обновления?

2) Если мне нужно сохранить исходный объект адаптера, нужно ли мне также оставить доступным и открытым объект подключения?

Я понимаю отключенную модель ADO.NET - я просто запутался в области объекта, когда пришло время обновить базу данных. Если бы кто-нибудь мог дать мне несколько советов о лучших практиках для этого сценария, я был бы очень признателен!

Заранее спасибо...

Ответов (3)

Решение

1) Вам не нужен тот же DataAdapter, но если вы создаете новый, он должен использовать тот же запрос, что и его основа.

2) DataAdapter откроет свое соединение, если соединение будет закрыто. В этом случае он снова закроет соединение после того, как это будет сделано. Если соединение уже открыто, оно останется открытым даже после его завершения.

Обычно вы будете работать так, как в вашем примере. Создайте Conneciton и DataAdapter, заполните DataTable и затем удалите Connection и DataAdapter.

Два комментария к вашему коду:

  • Здесь вам не нужен CommandBuilder, поскольку вы делаете только выбор. Построитель команд необходим только в том случае, если вы хотите автоматически генерировать операторы Insert, Update или Delete. В этом случае вам также необходимо вручную установить InsertCommand, UpdateCommand или DeleteCommand в DataAdapter из CommandBuilder.
  • Второй. Вместо того, чтобы вызывать Dispose вручную, вы должны использовать предложение Using. Это гарантирует, что ваши объекты будут удалены, даже если возникнет исключение.

Попробуйте изменить свой код на этот:

DataTable dt = new DataTable();
using (OleDbConnection conn = new OleDbConnection("my_connection_string"))
using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * from Employees", conn))
{
  adapter.Fill(dt);    
}

Обратите внимание, что я определяю DataTable вне предложений using. Это необходимо для того, чтобы таблица была в области видимости, когда вы оставите использование. Также обратите внимание, что вам не нужен вызов Dispose для DataAdapter или вызов Close для Connection. И то, и другое делается неявно, когда вы покидаете использование.

Ой. И добро пожаловать в SO :-)

Есть две дополнительные детали, которые стоит добавить к отличному ответу Руне Гримстад.

Во-первых, CommandBuilder (если он необходим) реализует IDisposable, поэтому его следует заключить в собственный оператор using. Удивительно (по крайней мере, для меня), Disposing the DataAdapter не похоже на Dispose связанный CommandBuilder. Проблема, которую я заметил, когда мне не удалось это сделать, заключалась в том, что, хотя я вызвал Dispose в DataAdapter и состояние подключения было «Closed», я не смог удалить временную базу данных после того, как использовал CommandBuilder для обновления этой базы данных.

Во-вторых, утверждение ... В этом случае вам также необходимо вручную установить InsertCommand, UpdateCommand или DeleteCommand в DataAdapter ... » не всегда правильно. Во многих тривиальных случаях CommandBuilder автоматически создает правильные операторы INSERT, UPDATE и DELETE на основе оператора SELECT, предоставленного DataAdapter, и метаданных из базы данных. «Тривиальный» в данном случае означает, что осуществляется доступ только к одной таблице, и эта таблица имеет первичный ключ, который возвращается как часть оператора SELECT.

Чтобы ответить на ваши вопросы:

  1. В идеале вы должны сохранить тот же DataAdapter, потому что он уже выполнил свою инициализацию. DataAdapter предоставляет такие свойства, как SelectCommand, UpdateCommand, InsertCommand и DeleteCommand, которые позволяют вам устанавливать различные объекты Command для выполнения этих различных функций в источнике данных. Итак, как видите, DataAdapter предназначен для повторного использования для нескольких команд (для одного и того же соединения с базой данных). Использование CommandBuilder (хотя и не рекомендуется) создает другие команды путем анализа SelectCommand, что позволяет вам выполнять обновления, удаления и вставки с использованием того же CommandBuilder.

  2. Лучше всего позволить DataAdapter неявно обрабатывать соединения с базой данных. @Rune Grimstad уже подробно рассказывал об этом неявном поведении, и это полезно понять. В идеале соединения должны быть закрыты как можно скорее.