Робота з автономними даними в, ado

Кондратьєв Денис
visualdesign.ru

Технологія ADO.NET, на відміну від своїх попередників ADO і OLE DB, була розроблена спеціально для використання в web додатках, де не буває постійних з'єднань з БД. Традиційна робота з даними в ADO.NET будується за такою схемою: створюється з'єднання Connection, потім воно відкривається методом Open, створюється об'єкт команда Command, інкапсулює SQL команду, вона виконується, а з'єднання потім закривається. Такий підхід забезпечує потоковий доступ до результатів запитів. Тобто Новомосковський дані за допомогою DataReader, ви не можете перестрибнути через кілька записів або повернутися до попередньої. Поточний доступ має максимальну продуктивність.
ADO.NET була розроблена для доступу до даних без реального з'єднання з БД. При цьому всі дані розміщуються в оперативній пам'яті. Робота з від'єднаними даними в ADO.NET здійснюється за допомогою класів з простору імен System.Data.

Самий Вижній клас при роботі з від'єднаними даними - це DataSet. Після того як отримані результати запиту за допомогою об'єкта DataAdapter і збережені в DataSet 'e, з'єднання між БД і об'єктом DataSet перестає існувати. Зміни в DataSet не позначаються на БД і навпаки. Клас DataSet включає в себе набір таблиць DataTable і зв'язків між таблицями DataRelation. Клас DataTable включає набір рядків DataRow, набір стовпців таблиці DataColumn, і набори відносин ChildRelations і ParentRelations між стовпцями різних таблиць бази даних. Клас DataRow инкапсулирует інформацію про рядку в таблиці і стан рядка Deleted, Modified, New і Unchanged. Клас Constraint використовується для збереження цілісності даних в таблицях.

Переваги роботи з від'єднаними даними:
1. не потрібно постійне з'єднання з БД, що потрібно, наприклад, для web додатків;
2. полегшується створення багаторівневих додатків. Якщо додаток звертається до БД за допомогою об'єктів рівня DAL, то бізнес об'єктів на рівні BLL можна передавати DataSet. Оновлення в БД також можуть передаватися за допомогою DataSet;
3. полегшується сортування, пошук, фільтрація і навігація за даними;
4. полегшується робота з реляційними даними;
5. є можливість кешувати зміни. Об'єкт DataSet дозволяє кешувати зміни і потім за допомогою DataAdapter передавати всі зміни в БД за 1 раз;
6. тісна інтеграція з XML. Вміст DataSet можна завантажувати і зберігати у вигляді XML документів.

Використання об'єктів DataSet

Нижче наводиться приклад використання об'єкта DataSet. Всі приклади в статті використовують БД Northwind БД MS SQL Server.

stringconn = "Provider = SQLSQL; Data Source = (local) \\ NetSDK; InitialCatalog = Northwind; Trusted_Connection = Yes;";
string query = "SELECT CustomerID, CompanyName, ContactName, Phone FROM Customers";
SqlDataAdapter da = new SqlDataAdapter (query, conn);
DataSet ds = new DataSet ();
da.Fill (ds, "Customers");

Спочатку створюємо рядок з'єднання з БД і SQL запит для отримання даних. DataAdapter поміщає результати запиту в відповідну таблицю DataTable, що знаходиться в DataSet. За допомогою переобтяженого методу Fill можна поміщати дані і безпосередньо в DataTable. Для однієї таблиці можна кілька разів викликати метод Fill, однак, якщо викликати метод Fill для DataSet без явної вказівки імені таблиці, то ці дані будуть поміщатися в різні таблиці (наприклад, "Table", "Table1", "Table2",). Для доступу до даних, що знаходяться в таблицю є властивість Rows, яке повертає набір об'єктів DataRow

DataTable table = ds.Tables [0];
DataRow row = table.Rows [0];
Console.WriteLine ( "OrderID:" + row [ "OrderID"]);
Console.WriteLine ( "CustomerID:" + row [ "CustomerID"]);

У об'єкта DataRow є властивість Item, яке повертає вміст конкретного поля. Можна вказати ім'я поля як в прикладі коду, або ціле число, відповідне порядковому номеру стовпчика. При пошуку за індексом дані трохи повертаються швидше, ніж при пошуку за назвою стовпчика.

Зміна вмісту DataTable

Для додавання нового рядка в таблицю існує метод NewRow (), який створює новий об'єкт DataRow, але не додає запис у таблицю. Полем нового запису задаються значення за замовчуванням або Null, якщо значення за замовчуванням не задано.

DataRow row = ds.Tables [ "Customers"]. NewRow ();
row [ "CustomerID"] = "VASYA";
row [ "Company"] = "Компанія";
row [ "ContactName"] = "Вася Пупкін";
row [ "Phone"] = "11-22-33";
ds.Tables [ "Customers"]. Rows.Add (row);

Є ще один спосіб додавання записів в таблицю - метод LoadDataRow (). Перший параметр цього методу - це масив значень, елементи якого відповідають стовпцям таблиці. Другий - дозволяє управляти значенням властивість RowState нового запису. Якщо передати false, то значення цієї властивості буде Added, як і при додаванні нового запису методом Add.

Редагування існуючої записи можна наступним чином:

DataRow row = ds.Tables [ "Customers"] [0];
row [ "ContactName"] = "Вася Пупкін";

або за допомогою методу ItemArray:

Для видалення запису потрібно викликати метод DataRow.Delete (). При цьому видалений запис фактично не видаляється з DataTable, а позначається як віддалена - її властивість RowState приймає значення Deleted. Якщо ж до виклику методу Delete значення RowState було Added, тотолько в цьому випадку рядок видаляється з таблиці.

Використання стовпців з Автоінкрементний

Для підтримки стовпців з автоматичним збільшенням значення у DataColumn є властивості AutoIncrement, AutoIncrementSeed і AutoIncrementStep. Для того, щоб створити стовпець DataColumn з автоінкрементом потрібно встановити властивість AutoIncrement в true. Значення лічильника буде починатися з AutoIncrementSeed (якщо це не порушує коректність даних в таблиці) і збільшуватися на значення AutoIncrementStep. Для стовпців з Автоінкрементний рекомендується встановлювати властивість ReadOnly в true. Нижче наведено приклад вставки в таблицю стовпця з автоінкрементом

DataColumn column = table.Columns.Add ( "CustomerID", typeof (Int32));
column.AutoIncrement = true;
column.AutoIncrementSeed = 1;
column.AutoIncrementStep = 1;

Якщо ви плануєте зносити зміни в БД методом DataAdapter.Update (), то рекомендується поставити властивостями AutoIncrementSeed і AutoIncrementStep значення -1. Це гарантує, що ADO.NET буде генерувати значення мітки, яких немає в БД. При виклику методу Update в БД внесуться вже унікальні значення.

Робота з DataSet в середовищі Visual Studio .NET

Створювати об'єкти DataSet можна як програмно, так і за допомогою середовища Visual Studio. Для другого випадку призначена вкладка Data в панелі інструментів. Для початку потрібно перетягнути на web або win-форму об'єкт SqlDataAdapter.

Робота з автономними даними в, ado

Потім в майстра створити нове підключення до БД, вказавши БД Northwind і спосіб доступу до БД як «Use SQL statements». Після цього виберіть таблицю Customers і відзначте всі стовпці таблиці.

Робота з автономними даними в, ado

Повторіть процес для таблиці Order, використовуючи вже готове з'єднання. Потім правою кнопкою миші по панелі з створеними DataAdapter 'ами, виберете з контекстного меню команду Generate DataSet.

Робота з автономними даними в, ado

Відзначте галочками обидва DataAdapter і натисніть на ОК.

Робота з автономними даними в, ado

Доданий об'єкт DataSet відобразився в панелі компонентів. Ми додали т.зв. DataSet зі строгим контролем типів (збірний DataSet), про який будемо говорити пізніше. Структуру даних можна подивитися в створеному файлі з розширенням xsd.

Робота з реляційними даними

Робота з реляційними даними здійснюється за допомогою об'єктів класу DataRelation, сполучні колонки DataColumn двох таблиць DataTable. Створити такий об'єкт можна наступним чином:

ds.Relationships.Add (new DataRelation ( "CustomersOrders", ds.Tables [ "Customers"]. Columns [ "CustomerID"], ds.Tables [ "Orders"]. Columns [ "CustomerID"]);

Якщо потрібно визначити ставлення, засноване на кілька стовпчиків, потрібно використовувати конструктор, який приймає масив об'єктів DataColumn:

DataTable tblParent = ds.Tables [ "ParentTable"];
DataColumn [] colsParent = new DataColumn [];
DataTable tblChild = ds.Tables [ "ChildTable"];
DataColumn [] colsChild = new DataColumn [];
ds.Relationships.Add (new DataRelation ( "ParentChild", colsParent, colsChild));

Робота зі зв'язаними даними

Основним застосуванням об'єктів DataRelation є пошук пов'язаних даних. Однак сам об'єкт DataRelation не надає такої функціональності, вона реалізується методами класу DataRow: GetChildRow (), GetParentRow () і GetParentRows ().
Для пошуку дочірніх записів використовується метод GetChildRow () відповідного об'єкта DataRow. Йому передається йому ім'я об'єкта DataRelation, що визначає ставлення. Цей метод повертає дочірні записи у вигляді масиву об'єктів DataRow.

DataRow row = ds.Tables [ "Customers"]. Rows [0];
foreach (DataRow rowOrder in row.GetChildRows ( "CustomersOrders"))
Console.WriteLine (rowOrder [ "OrderID"] + rowOrder [ "OrderDate"] + "\ n");

Знайти батьківську запис за допомогою DataRelation можна методом DataRow.GetParentRow ().

DataRow rowOrder = ds.Tables [ "Orders"]. Rows [0];
Console.WriteLine ( "\ t" + rowOrder.GetParentRow ( "CustomersOrders") [ "ContactName"] + "\ n");

У разі відносини «один до багатьох» знайти все батьківські записи конкретного об'єкта DataRow можна з методом GetParentRows (), що також бере назву відносини і повертає масив батьківських об'єктів.

Додавання об'єкта DataRelation в Visual Studio .NET

Для додавання відносини DataRelation в DataSet зі строгим контролем типів потрібно перейти до структури даних, клацнувши по файлу з розширенням xsd, що визначає структуру DataSet. Клацнувши на батьківський DataTable правою кнопкою потрібно в контекстному меню вибрати Add / New Relation.

Робота з автономними даними в, ado

У діалоговому вікні Edit Relation задаються батьківські і дочірні об'єкти.

Робота з автономними даними в, ado

При натисканні на ОК, в XML Sheme Designer з'являється графічне представлення DataRelation - лінія, що з'єднує 2 об'єкти.

Пошук записів

При запитах до БД часто потрібно знайти запис по її первинному ключу. Для пошуку записів в DataTable існує метод DataRowCollection.Find ().

table.PrimaryKey = new DataColumn [];
DataRow row = tbl.Rows.Find ( "VASYA");
if (row == null)
Console.WriteLine ( "Запис не знайдена");
else
Console.WriteLine (row [ "CompanyName"]);

Якщо первинний ключ складається з кількох колонок, то в метод Find () можна передати масив об'єктів.
Для виконання пошуку за довільним SQL запиту у DataTable є метод Find (). Наприклад, для отримання імен всіх покупців, які перебувають в Уфі, можна скористатися таким кодом

DataRow [] rows = table.Select ( "City = 'Уфа'");
foreach (DataRow row in rows)
Console.WriteLine (row [ "CompanyName"] + "\ n");

Якщо потрібно, щоб повертаються дані були розсортовані, можна скористатися перевантаженої версією цього методу. Вона імітує розділ ORDER BY SQL-запит.

DataRow [] rows = table.Select ( "City = 'Уфа'", "CompanyName ASC");

Робота з об'єктами DataSet зі строгим контролем типів

Раніше ми вже створювали об'єкти DataSet зі строгим контролем типів. Розглянемо, які нові функції з'явилися у типизированного DataSet.

Додавання запису

Всі класи, відповідні таблицями DataTable в DataSet, дозволяють додавати нові записи двома способами. Метод New [ім'я_таблиці] Row () повертає новий рядок в таблиці:

DataSetTest ds = new DataSetTest ();
DataSetTest.CustomersDataTable tblCustomers = ds.Customers;
DataSetTest.CustomersRow rowCustomer = tblCustomers.NewCustomersRow ();
rowCustomer.CustomerID = "VASYA";
rowCustomer.CompanyName = "Компанія";
rowCustomer.ContactName = "Вася Пупкін";
rowCustomer.Phone = "11-22-33";
tblCustomers.AddCustomersRow (rowCustomer);

Другий спосіб - це використовувати метод Add [ім'я_таблиці] Row (), який приймає масив об'єктів, відповідних полів запису:

DataSetTest ds = new DataSetTest ();
DataSetTest.CustomersDataTable.AddCustomersRow ( "VASYA", "Компанія", "Вася Пупкін", "11-22-33");

Пошук запису

Пошук запису в таблиці теж зазнав змін. Наприклад, для пошуку в таблиці Order Details по складеному ключу з'явився метод наступний метод

DataSetTest.Order_DetailRow = tblDetails.FindByOrderIDProductID (112233, 456);

Також типізовані DataSet підтримують українські літери в назвах таблиць і полів таблиць.

ds.Статістіка.AddСтатістікаRow (15.9, "компанія", true);

Передача оновлень в БД

Для передачі змін в БД використовується об'єкти DataAdapter. Для створення логіки поновлення БД можна використовувати один з трьох варіантів:
1. вручну конфігурувати DataAdapter в період розробки;
2. скористатися об'єктом CommandBulder в період виконання;
3. використовувати в період розробки DataAdapter Configuration Wizard.

Ручне конфігурування DataAdapter

DataAdapter має 3 властивості для передачі змін в БД: InsertCommand, UpdateCommand і DeleteCommand. Значення цих властивості повинні бути задані до виклику методу DataAdapter.Update () з урахуванням того, які зміни були внесені в DataSet. Коли метод Update () додає, оновлює або видаляє рядки в таблиці, він викликає відповідну команду.
Якщо в ході ваших дій ви тільки додавали рядки в таблицю, то і задати ви повинні тільки значення InsertCommand. Нижче наведено код для такої ситуації:

string conn = "Provider = SQLSQL; Data Source = (local) \\ NetSDK; Initial Catalog = Northwind; Trusted_Connection = Yes;";
string query = "SELECT CustomerID, CompanyName, ContactName, Phone FROM Customers"; SqlDataAdapter da = new SqlDataAdapter (query, conn); DataSet table = new DataSet (); da.Fill (table, "Customers");

// додаємо нові рядки в таблицю
.

// створюємо команду для вставки нових записів
query = "INSERT INTO Customers (CustomerID, CompanyName, ContactName, Phone) VALUES (.)";
SqlCommand cmd = new SqlCommand (query, conn);
SqlParameterCollection pc = cmd.Parameters; pc.Add ( "CustomerID", SqlType.Integer, 0, "CustomerID");
pc.Add ( "CompanyName", SqlType.String, 0, "CompanyName");
pc.Add ( "ContactName", SqlType.String, 0, "ContactName");
pc.Add ( "Phone", SqlType.String, 0, "Phone");
da.InsertCommand = cmd;
da.Update (table);

Подібний підхід може застосовуватися і при передачі оновлень в БД за допомогою збережених процедур. Припустимо, що ім'я процедури для додавання нового покупця це spInsertCustomer. Тоді наш код змінитися наступним чином:

OleDbCommand cmd = new OleDbCommand ( "spInsertCustomer", conn);
cmd.CommandType = CommandType.StoredProcedure;
OleDbParameterCollection pc = cmd.Parameters;
pc.Add ( "CustomerID", SqlType.Integer, 0, "CustomerID");
pc.Add ( "CompanyName", SqlType.String, 0, "CompanyName");
pc.Add ( "ContactName", SqlType.String, 0, "ContactName");
pc.Add ( "Phone", SqlType.String, 0, "Phone");

Використання CommandBuilder

CommandBuilder генерує SQL запити звертаючись до БД для отримання метаданих про таблиці. Для використання CommandBuilder необхідне виконання наступних умов: 1. запит повертає дані тільки з однієї таблиці;
2. в таблиці визначено первинний ключ;
3. первинний ключ є в результатах запиту.
Нижче наведено приклад використання CommandBuilder.

string con = "Provider = SQLOLEDB; Data Source = (local) \\ NetSDK; InitialCatalog = Northwind; Trusted_Connection = Yes;";
string query = "SELECT OrderID, ProductID, Quantity, UnitPrice FROM [Order Details]";
OleDbDataAdapter da = new OleDbDataAdapter (strSQL, strConn);
OleDbCommandBuilder cb = new OleDbCommandBuilder (da);
da.InsertCommand = cb.GetInsertCommand ();
da.Update (tbl);

Використання майстра Data Adapter Configuration Wizard

Одне з призначень майстра - створення логіки поновлення бази даних. На четвертому кроці майстра по команді Advanced Options виводиться діалог, в якому можна вказати створювати чи ні команди для вставки, оновлення та видалення записів в БД.

Робота з автономними даними в, ado

На третьому ж етапі роботи майстер можна вказати спосіб передачі поновлення в БД: за допомогою SQL запитів, за допомогою існуючої процедури, або створення нової процедури, що. Ніяких додатковий дій для створення логіки оновлення не потрібно.

Робота з автономними даними в, ado

Схожі статті