Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5636 / 790 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 18:

Основы ADO .NET

< Лекция 17 || Лекция 18: 123456789101112

DataSet в свободном полете

DataSet myDataSet = new DataSet();
 // Пустой объект - представитель класса DataSet.
 DataTable myTable = new DataTable(); // Пустая таблица создана.
 myDataSet.Tables.Add(myTable); // И подсоединена к объекту класса DataSet.
 // Определение структуры таблицы. Это мероприятие можно было
 // провести и до присоединения таблицы. 
 DataColumn shipColumn = new DataColumn("Ships");
 myDataSet.Tables[0].Columns.Add(shipColumn);
  
 // Прочие столбцы подсоединяются аналогичным образом.
 // Таким образом формируются поля данных таблицы.
 // Внимание! После того как определена структура таблицы,
 // то есть определены ВСЕ СТОЛБЦЫ таблицы, от имени этой конкретной
 // таблицы порождается объект-строка. Этот объект сразу располагается
 // непосредственно в таблице. Для каждой определенной таблицы
 // метод NewRow() порождает строку
 // (последовательность значений соответствующего типа). 
 // Для непосредственного
 // редактирования вновь созданной строки запоминается ее ссылка. 
 // Работать со строкой через эту ссылку проще, чем с массивом
 // строк таблицы.
 DataRow myRow = myDataSet.Tables[0].NewRow();

 // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

 // Остается заполнить строку таблицы содержательной информацией.
 // При этом может быть использован любой источник данных.
 // В данном примере предполагается наличие объекта типа ArrayList 
 // с именем ShipCollection.
 for (int i = 0; i < ShipCollection.Count; i++)
 {
 myRow.Item[Counter] = ShipCollection[i];
 } 

 // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 // Заполненный объект - представитель класса DataRow добавляется 
 // к набору Rowsкласса DataTable.
 myDataSet.Tables[0].Rows.Add(myRow);
Листинг 18.7.

Естественно, что данная последовательность действий может повторяться сколь угодно много раз, пока не будут созданы и не заполнены все члены объекта DataSet.

Далее будет рассмотрен пример использования объекта DataSet для прочтения информации из текстового файла. При этом используется метод класса string Split(), который обеспечивает выделение из исходной строки подстрок с их последующим преобразованием в символьные массивы. Критерием выделения подстроки является массив символов-разделителей или целочисленное значение, определяющее максимальную длину подстроки.

Применение класса DataSet

using System;
 using System.Data;

 namespace mergeTest
 {
 class Class1
 {
 static void Main(string[] args)
 {
 // Создается объект DataSet. 
 DataSet ds = new DataSet("myDataSet");

 // Создается таблица. 
 DataTable t = new DataTable("Items");

 // Столбцы таблицы – это особые объекты.
 // Имя первого столбца – id, тип значения – System.Int32.
 DataColumn c1 = new DataColumn("id", Type.GetType("System.Int32"));
 c1.AutoIncrement=true;
 // Имя второго столбца – Item, тип значения – System.Int32.
 DataColumn c2 = new DataColumn("Item", Type.GetType("System.Int32"));


 // Сборка объекта DataSet:
 // Добавляются объекты-столбцы...   
 t.Columns.Add(c1);
 t.Columns.Add(c2);


 // А вот массив столбцов (здесь он из одного элемента)
 // для организации первичного ключа (множества первичных ключей).
 DataColumn[] keyCol= new DataColumn[1];

 // И вот, собственно, как в таблице задается множество первичных ключей.
 keyCol[0]= c1;
 // Свойству объекта t передается массив, содержащий столбцы, которые
 // формируемая таблица t будет воспринимать как первичные ключи.
 t.PrimaryKey=keyCol;
 // А что с этими ключами будет t делать? А это нас в данный момент
 // не касается. Очевидно, что методы, которые обеспечивают контроль
 // над информацией в соответствии со значениями ключей, уже где-то
 // "зашиты" в классе DataTable. Как и когда они будут выполняться – 
 // не наше дело. Наше дело – указать на столбцы, которые для данной
 // таблицы будут ключевыми. Что мы и сделали.

 // Таблица подсоединяется к объекту ds – представителю класса DataSet.
 ds.Tables.Add(t);

 DataRow r;

 // В таблицу, которая уже присоединена к
 // объекту ds DataSet, добавляется 10 rows.
 for(int i = 0; i <10;i++)
 {
 r=t.NewRow();
 r["Item"]= i;
 t.Rows.Add(r);
 }

 // Принять изменения.
 // Так производится обновление DataSet'а.
 // Сведения о новых изменениях и добавлениях будут фиксироваться
 // вплоть до нового обновления.
 ds.AcceptChanges();
 PrintValues(ds, "Original values");

 // Изменение значения в первых двух строках.
 t.Rows[0]["Item"]= 50;
 t.Rows[1]["Item"]= 111;
 t.Rows[2]["Item"]= 111;

 // Добавление еще одной строки.
 // Судя по всему, значение первого столбца устанавливается автоматически.
 // Это ключевое поле со значением порядкового номера строки.
 r=t.NewRow();
 r["Item"]=74;
 t.Rows.Add(r);


 // Объявляем ссылку для создания временного DataSet. 
 DataSet xSet;

 // ДЕКЛАРАЦИЯ О НАМЕРЕНИЯХ КОНТРОЛЯ ЗА КОРРЕКТНОСТЬЮ ЗНАЧЕНИЙ СТРОКИ. 
 // Вот так добавляется свойство, содержащее строку для описания 
 // ошибки в значении. Наш DataSet содержит одну строку с описанием.
 // Это всего лишь указание на то обстоятельство, что МЫ САМИ 
 // обязались осуществлять
 // некоторую деятельность по проверке чего-либо. Чтобы не забыть, 
 // в чем проблема,
 // описание возможной ошибки (в свободной форме!) добавляем 
 // в свойства строки,
 // значения которой требуют проверки.
 t.Rows[0].RowError= "over 100 (ЙЦУКЕН!)";
 t.Rows[1].RowError= "over 100 (Stupid ERROR!)";
 t.Rows[2].RowError= "over 100 (Ну и дела!)";
 // Но одно дело – декларировать намерения, а другое – осуществлять 
 // контроль.
 // Проблема проверки корректности значения – наша личная проблема.
 // Однако о наших намерениях контроля за значениями становится 
 // известно объекту – представителю DataSet!

 PrintValues(ds, "Modified and New Values");

 // Мы вроде бы согласились проводить контроль значений.
 // Даже декларировали некий принцип проверки. 
 // Однако ничего само собой не происходит.
 // Так вот,
 //
 // ЕСЛИ В ТАБЛИЦУ БЫЛИ ДОБАВЛЕНЫ СТРОКИ ИЛИ ИЗМЕНЕНЫ ЗНАЧЕНИЯ СТРОК
 // И
 // МЫ ОБЯЗАЛИСЬ КОНТРОЛИРОВАТЬ ЗНАЧЕНИЯ СТРОК В ТАБЛИЦЕ,
 //
 // то самое время организовать эту проверку...
 // Критерий правильности значений, естественно, наш!
 // Алгоритмы проверки – тоже НАШИ!
 // Единственное, чем нам может помочь ADO .NET, – это выделить
 // подмножество строк таблицы,
 // которые были добавлены или модифицированы со времени последнего
 // обновления нашего объекта - представителя DataSet'а,

 if(ds.HasChanges(DataRowState.Modified | DataRowState.Added)& ds.HasErrors)
 {
 // И для этого мы воспользуемся методом, который позволяет обеспечить
 // выделение подмножества добавленных и
 // модифицированных строк в новый объект DataSet'а.
 // Use GetChanges to extract subset.
 xSet = ds.GetChanges(DataRowState.Modified|DataRowState.Added);
 PrintValues(xSet, "Subset values");
 // Insert code to reconcile errors. In this case, we'll reject changes.
 // Вот, собственно, код проверки. Все делается своими руками.
 foreach(DataTable xTable in xSet.Tables)
 {
 if (xTable.HasErrors)
 {
 foreach(DataRow xRow in xTable.Rows)
 {
 // Выделенное подмножество проверяем на наличие
 // ошибочного значения (для нас все, что больше 100, – 
 // уже ошибка!) 
 Console.Write(xRow["Item"] + "  ");
 if((int)xRow["Item",DataRowVersion.Current ]> 100)
 {
 // Находим ошибку в строке, сообщаем о ней,               
 Console.WriteLine("Error! – " + xRow.RowError);
 // Возвращаем старое значение...
 xRow.RejectChanges();
 // Отменяем значение свойства - уведомителя о возможных
 // ошибках для данной строки...
 xRow.ClearErrors();
 }
 else
 Console.WriteLine("OK.");
 }
 }
 }

 PrintValues(xSet, "Reconciled subset values");

 // Сливаем измененные и откорректированные строки в основной 
 // объект – DataSet
 // Merge changes back to first DataSet.
 ds.Merge(xSet);

 PrintValues(ds, "Merged Values");
 }
 }

 // А это всего лишь вывод содержимого DataSet'а.
 private static void PrintValues(DataSet ds, string label)
 {
 Console.WriteLine("\n" + label);
 foreach(DataTable t in ds.Tables)
 {
 Console.WriteLine("TableName: " + t.TableName);
 foreach(DataRow r in t.Rows)
 {
 foreach(DataColumn c in t.Columns)
 {
 Console.Write("\t " + r[c] );
 }
 Console.WriteLine();
 }
 }
 }
 }
 }
Листинг 18.8.

Подсоединенные объекты модели ADO .NET. Провайдеры

Поставщик данных для приложения (Провайдер) – объект, предназначенный для обеспечения взаимодействия приложения с хранилищем информации (базами данных).

Естественно, приложению нет никакого дела до того, где хранится и как извлекается потребляемая приложением информация. Для приложения источником данных является тот, кто передает данные приложению. И как сам этот источник эту информацию добывает – никого не касается.

Источник данных ( Data Provider ) – это набор взаимосвязанных компонентов, обеспечивающих доступ к данным. Функциональность и само существование провайдера обеспечивается набором классов, специально для этой цели разработанных.

ADO .NET поддерживает два типа источников данных, соответственно, два множества классов:

  • SQL Managed Provider (SQL Server.NET Data Provider) – для работы с Microsoft SQL Server 7.0 и выше. Работает по специальному протоколу, называемому TabularData Stream (TDS) и не использует ни ADO, ни ODBC, ни какую-либо еще технологию. Ориентированный специально на MS SQL Server, протокол позволяет увеличить скорость передачи данных и тем самым повысить общую производительность приложения;
  • ADO Managed Provider (OleDb.NET Data Provider) – для всех остальных баз данных. Обеспечивает работу с произвольными базами данных. Однако за счет универсальности есть проигрыш по сравнению с SQL Server Provider, так что при работе с SQL Server рекомендовано использовать специализированные классы.

В следующих разделах приводится описание составных элементов провайдера.

Connection

Объект – представитель класса Connection представляет соединение с источником (базой) данных и обеспечивает подключение к базе данных. Visual Studio .NET поддерживает два класса:

  • SQLConnection (обеспечивает подключение к SQL Server 7.0 и выше),
  • OleDbConnection (обеспечивает подключение к прочим вариантам БД).

Компонента Connection (независимо от того, представителем какого класса она является) имеет свойство ConnectionString, в котором фиксируется вся необходимая для установления соединения с БД информация. Кроме того, поддерживается ряд методов, позволяющих обрабатывать данные с применением транзакций.

Свойства объекта Connection позволяют:

  • задавать реквизиты пользователя;
  • указывать расположение источника данных.

Методы объекта позволяют управлять соединением с источником данных.

В процессе соединения с помощью объекта – представителя класса OleDbConnection (аналогично SQLConnection) создается и инициализируется соответствующий объект с использованием одного из вариантов конструктора и строки соединения.

Формирование строки и последовательность действий при инициализации объекта соединения – дело техники. Главное – это чтобы свойство ConnectionString в результате получило бы ссылку на строку символов, содержащую необходимую для установления соединения информацию.

// Объявили и определили объект соединения. 
 private System.Data.OleDb.OleDbConnection oleDbConnection1;
 this.oleDbConnection1 = new System.Data.OleDb.OleDbConnection();

 ::::::::::

 // Настроили объект соединения.
 // Для наглядности необходимая для установления соединения
 // информация представлена серией строк.
 oleDbConnection1.ConnectionString =
 @"Jet OLEDB:Global Partial Bulk Ops=2;" + 
 @"Jet OLEDB:Registry Path=;" + 
 @"Jet OLEDB:Database Locking Mode=1;" + 
 @"Data Source=""F:\Users\Work\CS\DB.BD\DBTests\Lights.mdb"";" + 
 @"Jet OLEDB:Engine Type=5;" + 
 @"Jet OLEDB:Global Bulk Transactions=1;" + 
 @"Provider=""Microsoft.Jet.OLEDB.4.0"";" + // Поставщик 
 @"Jet OLEDB:System database=;" + 
 @"Jet OLEDB:SFP=False;" + 
 @"persist security info=False;" + 
 @"Extended Properties=;" + 
 @"Mode=Share Deny None;" + 
 @"Jet OLEDB:Create System Database=False;" + 
 @"Jet OLEDB:Don't Copy Locale on Compact=False;" + 
 @"Jet OLEDB:Compact Without Replica Repair=False;" + 
 @"User ID=Admin;" +
 @"Jet OLEDB:Encrypt Database=False";
Листинг 18.9.

Свойства, методы и события класса OleDbConnection

Свойства
ConnectionString string Строка, определяющая способ подключения объекта к источнику данных
ConnectionTimeout Int32 Интервал времени, в течение которого объект пытается установить соединение с источником данных (только для чтения)
Container string Get. Возвращает объект IContainer, который содержит объект Component
Database string Gets текущей базы данных или базы, которая использовалась после установления соединения
DataSource string Get. Имя сервера или имя файла-источника данных. Все зависит от того, с каким хранилищем информации ведется работа. Серверное хранилище данных (SQL Server, Oracle) – имя компьютера, выступающего в роли сервера. Файловые БД (Access) – имя файла
Provider string Gets имя OLE DB провайдера, которое было объявлено в " Provider= ..." clause строки соединения
ServerVersion string Get. Строка с информацией о версии сервера, с которым было установлено соединение
Site string Get или set. Объект ISite с информацией о функциональных возможностях узла
State string Gets текущее состояние соединения

Текущее состояние соединения кодируется как элемент перечисления ConnestionState. Список возможных значений представлен ниже.

Имя члена Описание Value
Broken Соединение с источником данных разорвано.Подобное может случиться только после того, как соединение было установлено. В этом случае соединение может быть либо закрыто, либо повторно открыто 16
Closed Соединение закрыто 0
Connecting Идет процесс подключения (значение зарезервировано) 2
Executing Соединение находится в процессе выполнения команды (значение зарезервировано.) 4
Fetching Объект соединения занят выборкой данных (значение зарезервировано) 8
Open Соединение открыто 1
Открытые методы
BeginTransaction Перегружен. Начинает транзакцию базы данных
ChangeDatabase Изменяет текущую базу данных для открытого OleDbConnection
Close Закрывает подключение к источнику данных. Это рекомендуемый метод закрытия любого открытого подключения
CreateCommand Создает и возвращает объект OleDbCommand, связанный с OleDbConnection
CreateObjRef (унаследовано от MarshalByRefObject ) Создает объект, который содержит всю необходимую информацию для конструирования прокси-сервера, используемого для коммуникации с удаленными объектами
Dispose (унаследовано от Component ) Перегружен. Освобождает ресурсы, используемые объектом Component
EnlistDistributed Зачисляет в указанную транзакцию в качестве Transaction распределенной транзакции
Equals (унаследовано от Object ) Перегружен. Определяет, равны ли два экземпляра Object
GetHashCode (унаследовано от Object ) Служит хэш-функцией для конкретного типа, пригоден для использования в алгоритмах хэширования и структурах данных, например в хэш-таблице
GetLifetimeService (унаследовано от MarshalByRefObject ) Извлекает служебный объект текущего срока действия, который управляет средствами срока действия данного экземпляра
GetOleDbSchemaTable Возвращает сведения схемы из источника данных так же, как указано в GUID, и после применения указанных ограничений
GetType (унаследовано от Object ) Возвращает Type текущего экземпляра
InitializeLifetimeService (унаследовано от MarshalByRefObject ) Получает служебный объект срока действия для управления средствами срока действия данного экземпляра
Open Открывает подключение к базе данных со значениями свойств, определяемыми ConnectionString
ReleaseObjectPoolOleDb Connection Статический. Означает, что пул объектов может быть освобожден, когда последнее основное подключение будет освобождено
ToString (унаследовано от Object ) Возвращает String, который представляет текущий Object
Защищенные методы
Dispose Перегружен. Переопределен. Освобождает ресурсы, используемые объектом OleDbConnection
Finalize (унаследовано от Component ) Переопределен. Освобождает неуправляемые ресурсы и выполняет другие действия по очистке, перед тем как пространство, которое использует Component, будет восстановлено сборщиком мусора.

В языках C# и C++ для функций финализации используется синтаксис деструктора

GetService (унаследовано от Component ) Возвращает объект, представляющий службу, которую предоставляет Component или его Container
MemberwiseClone (унаследовано от Object ) Создает неполную копию текущего Object
События
Disposed Это событие сопровождает процесс удаления объекта
InfoMessage Некоторые СУБД (SQL Server) поддерживают механизм информационных сообщений. Это событие происходит при отправке провайдером некоторых сообщений
StateChange Возникает при изменении состояния соединения
< Лекция 17 || Лекция 18: 123456789101112
kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2