
- •А.А. Волосевич
- •4. БАзы данных и технология ado.Net 3
- •4. БАзы данных и технология ado.Net
- •4.1. Архитектура ado.Net
- •4.2. Соединение с базой данных
- •4.3. Выполнение команд и запросов к базе данных
- •4.4. Параметризированные запросы
- •4.5. Чтение данных и объект DataReader
- •4.6. Рассоединенный набор данных
- •4.7. Объект класса DataColumn – колонка таблицы
- •4.8. Объекты класса DataRow – строки таблицы
- •4.9. Работа с объектом класса DataTable
- •4.10. Схема данных и типизированные dataset
- •4.11. Навигация, Поиск и фильтрация данных в DataSet
- •4.12. Класс DataView
- •4.13. Заполнение Рассоединенного набора данных
- •4.14. СиНхронизация набора данных и базы
- •4.15. Работа с транзакциями
4.13. Заполнение Рассоединенного набора данных
Каждый поставщик данных содержит класс, описывающий адаптер данных. В частности, поставщик для MS SQL Server имеет класс SqlDataAdapter. Адаптер данных является своеобразным мостом между базой данных и DataSet. Он позволяет записывать данные из базы в набор и производит обратную операцию. В принципе, подобные действия вполне осуществимы при помощи команд и ридеров. Использование адаптера данных – более унифицированный подход.
Основными свойствами адаптера являются SelectCommand, InsertCommand, DeleteCommand и UpdateCommand. Это объекты класса Command для выборки данных и обновления базы. При помощи метода адаптера Fill() происходит запись данных из базы в DataSet или таблицу, метод Update() выполняет перенос данных в базу.
В начале работы с адаптером его нужно создать и инициализировать свойства-команды1. Адаптер содержит несколько перегруженных конструкторов. Варианты вызова конструктора адаптера показаны в примере кода:
// 1. Обычный конструктор без параметров.
// Необходимо заполнить команды вручную
var da_1 = new SqlDataAdapter();
// 2. В качестве параметра конструктора – объект-команда
var cmd = new SqlCommand("SELECT * FROM Songs");
var da_2 = new SqlDataAdapter(cmd);
// 3. Параметры: текст запроса для выборки и объект-соединение
var con = new SqlConnection("Server=(local);. . .");
var da_3 = new SqlDataAdapter("SELECT * FROM Songs", con);
// 4. Параметры – строка запроса и строка соединения
var s = "SELECT * FROM Songs";
var c = "Server=(local);. . .";
var da_4 = new SqlDataAdapter(s, c);
Любой адаптер должен иметь ссылку на соединение с базой данных. Адаптер использует то соединение, которое задано в его объектах-командах.
Итак, адаптер создан. Теперь можно использовать его метод Fill() для заполнения некоторого набора данных:
var da = new SqlDataAdapter();
DataSet ds = new DataSet();
// Строго говоря, метод Fill() - функция, возвращающая
// число строк (записей), добавленных в DataSet
da.Fill(ds);
Заметим, что вызов метода Fill() не нарушает состояние соединения с БД. Если соединение было открыто до вызова Fill(), то оно останется открытым и после вызова. Если соединение было не установлено, метод Fill() откроет соединение, произведет выборку данных и закроет соединение. Так же ведут себя и все остальные методы адаптера, работающие с базой.
Поведение адаптера при заполнении DataSet зависит от настроек адаптера и от наличия схемы в объекте DataSet. Пусть при помощи адаптера заполняется пустой DataSet. В этом случае адаптер создаст в DataSet минимальную схему, используя имена и тип столбцов из базы и стандартные имена для таблиц. В результате выполнения следующего кода в ds будет создана одна таблица с именем Table1.
var da = new SqlDataAdapter("SELECT * FROM Songs", "Server=...");
var ds = new DataSet();
da.Fill(ds);
Команда выборки данных может быть настроена на получение нескольких таблиц. В следующем примере в пустой DataSet помещаются две таблицы с именами Table и Table1:
var cmd_text = "SELECT * FROM Songs; SELECT * FROM Albums";
var da = new SqlDataAdapter(cmd_text, "Server=...");
var ds = new DataSet();
da.Fill(ds);
Адаптер имеет свойство-коллекцию TableMappings, которое позволяет сопоставить имена таблиц базы и таблиц DataSet. Любой элемент коллекции TableMappings содержит свойство ColumnMappings, которое осуществляет отображение имен столбцов:
var cmd_text = "SELECT * FROM Songs; SELECT * FROM Albums";
var da = new SqlDataAdapter(cmd_text, "Server=...");
DataTableMapping dtm;
dtm = da.TableMappings.Add("Table1", "Disks");
dtm.ColumnMappings.Add("id", " Disks_id");
dtm.ColumnMappings.Add("title", " Disks_name");
Предположим, что заполняемый набор данных уже обладает некой схемой. Адаптер содержит свойство MissingSchemaAction, значениями которого являются элементы одноименного перечисления. По умолчанию значение свойства – Add. Это означает добавление в схему новых столбцов, если они в ней не описаны. Возможными значениями являются также Ignore (игнорирование столбцов, не известных схеме) и Error (если столбцы не описаны в схеме, генерируется исключение).
Обсудим дополнительные возможности адаптера, связанные с заполнением DataSet. Адаптер имеет метод FillSchema(), который переносит схему таблиц запроса в DataSet. Метод FillSchema() получает из базы имена и типы всех задействованных в запросе столбцов. Кроме этого, данный метод получает сведения о допустимости для столбца значений Null и задает значение свойства AllowDBNull создаваемых им объектов DataColumn. Метод FillSchema() также пытается определить на объекте DataTable первичный ключ.
Адаптер данных имеет три события:
-
FillError – событие наступает, если при заполнении DataSet адаптер столкнулся с какой-либо ошибкой;
-
RowUpdating – событие наступает перед передачей измененной строки в базу данных;
-
RowUpdated – событие наступает после передачи измененной записи в базу данных.