BindingSource
С выходом Net 2.0 технология Data Binding получила свое дальнейшее развитие. Появился новый класс BindingSource. Он является прокси-объектом между поставщиками данных и элементами управления, отображающими эти данные. Теперь элемент управления привязывается не к объектам, поставляющим данные (DataTable, DataSet, DataView), а к объекту BindingSource. Это позволяет использовать привязку ещё незагруженных данных, а также синхронизировать данные в случае использования общего BindingSource для нескольких элементов управления.
Продолжая построение нашего приложения, приведу, на мой взгляд, яркий пример, который демонстрирует все преимущества объекта BindingSource.
Добавим на форму новый элемент управления DataGridView. Давайте попробуем отобразить в нем список проектов, у которых текущий служащий, выбранный в ComboBox-e, был руководителем. Известно, что таблицы PROJECT и EMPLOYEE связаны между собой через поле TEAM_LEADER по внешнему ключу INTEG_36. Воспользуемся уже знакомым механизмом связи элемента управления и источника данных:
Необходимо найти в списке возможных источников данных уже использованный мной ранее BindingSource для таблицы служащих EMPLOYEE и запросить дизайнер создать новый BindingSource для связи между проектами и служащими по внешнему ключу INTEG_36:
Добавим элемент TextBox для отображения описания проекта, которое хранится в BLOB поле PROJECT_DESCR таблицы PROJECT. Для того, чтобы связать его с текущим проектом, в списке DataGridView необходимо установить Binding для свойства Text:
DataTableReader
Данный класс позволяет использовать объект DataTable в режиме однонаправленного ForwardOnly чтения. Он, так же как и OleDbDataReader, наследуется от базового класса DBDataReader. Этот способ чтения таблиц DataSet может быть полезен, когда используются общие методы для отсоединенного источника данных и данных, которые формируются методом OleDbCommand.ExecuteReader() в подсоединенном режиме. Следующий пример демонстрирует использование общего метода PrintDBDataReader() для подсоединенного и отсоединенного режимов работы:
public void GetDBReaderFromDataTable() { DataSet ds = new DataSet(); DataTable tbl = ds.Tables.Add("EMPLOYEE");
//загрузка данных в dataSet OleDbConnection con = ConnectionProvider.CreateConnection(); con.Open(); OleDbTransaction trans = con.BeginTransaction();
ds.Load(new OleDbCommand( "select * from EMPLOYEE",con,trans).ExecuteReader(), LoadOption.OverwriteChanges, tbl);
//используем DataTable в режиме однонаправленного чтения
this.PrintDBDataReader(new DataTableReader(tbl));
//OleDbDataReader и подсоединенный режим
this.PrintDBDataReader( new OleDbCommand("select * from EMPLOYEE", con, trans).ExecuteReader());
trans.Commit(); con.Close(); }
/// <summary>
/// Выводит в консоль данные из DBDataReader
/// </summary>
/// <param name="reader"></param>
public void PrintDBDataReader(System.Data.Common.DbDataReader reader) { while (reader.Read()) { Console.WriteLine("*********************************"); for (int i = 0; i < reader.FieldCount; i++) Console.WriteLine(reader.GetName(i) + "=" + reader[i].ToString()); }
reader.Close(); }
DDL запросы. CREATE/ALTER/DROP
Данный вид запросов позволяет управлять метаданными БД. Вы можете создавать, удалять и модифицировать колонки, таблицы и целые базы данных через SQL выражения, в тексте которых содержатся DDL-инструкции. Если применять их совместно со схемами метаданных, то можно без особых усилий копировать структуры существующих баз данных и создавать новые.
Все DDL запросы, за исключением CREATE DATABASE и DROP DATABASE, могут выполняться как в режиме автоматического подтверждения, так и в контексте транзакции. По умолчанию фиксирование изменений произведенных DDL запросами отключено. Это сделано из соображений безопасности. Для того, чтобы включить подтверждение DDL запросов, необходимо установить свойство auto_commit_ddl. Его описание есть в разделе «Методы подключения к базе данных» этой статьи.
Приведу пример использования DROP DATABASE для удаления базы данных:
private void DropDatabase() { if (File.Exists(databasePath)) { OleDbConnectionStringBuilder builder = CreateConnectionStringBuilderForSample();
//отключаем использование пула для этого подключения
builder.OleDbServices = OleDbServicesValues.EnableAll & ~OleDbServicesValues.ResourcePooling;
OleDbConnection con = new OleDbConnection(builder.ToString()); con.Open();
new OleDbCommand("drop database",con).ExecuteNonQuery(); con.Close(); } }
Обратите внимание на то, что для подключения, которое будет использоваться для удаления базы данных, мы отключили использование пула ресурсов. IBProvider умеет информировать сервисы Ole Db о ставших недоступными подключениях и в данном случае это действие является избыточным. Но оно оставлено здесь для решения возможных проблем при использовании Ole Db провайдеров других производителей.
Теперь DDL для создания новой базы данных:
private OleDbConnection CreateDatabase() { //подключение к существующей бд employee.gdb
OleDbConnection con = ConnectionProvider.CreateConnection(); con.Open();
//создание новой базы данных
new OleDbCommand( "create database '" + server_name + ":" + databasePath + "'\n" + "USER '" + user_name + "' \n" + "PASSWORD '" + password + "' \n", con).ExecuteNonQuery();
con.Close();
return new OleDbConnection( CreateConnectionStringBuilderForSample().ToString()); }
И, наконец, законченный пример, который сначала удаляет базу данных, потом создает на её месте новую и определяет в ней две таблицы, связанные внешним ключом:
public void CreateNewDBSample() { DropDatabase();
OleDbConnection con = CreateDatabase(); con.Open(); OleDbTransaction trans = con.BeginTransaction();
//создаем таблицу SAMPLE_TABLE с двумя колонками
ExecuteDDL( "CREATE TABLE SAMPLE_TABLE( " + //int column " ID INTEGER NOT NULL, " + //varchar column
" NAME VARCHAR(64), " + //primary key
"CONSTRAINT PK_SAMPLE_TABLE PRIMARY KEY(ID) )", trans);
//создаем SAMPLE_TABLE_2 связанную через FOREIGN KEY ExecuteDDL( "CREATE TABLE SAMPLE_TABLE_2 ( " + " ID INTEGER NOT NULL, " + //int columns
" PARENT INTEGER NOT NULL, " + //int column
"CONSTRAINT PK_SAMPLE_TABLE_2 PRIMARY KEY(ID), " + //primary key
"CONSTRAINT FK_SAMPLE_TABLE_PARENT " + //foreign key
"FOREIGN KEY(PARENT) REFERENCES SAMPLE_TABLE(ID))", trans);
trans.Commit(); con.Close(); }
Добавление логики управления данными
Мы разобрались как отображать, связывать и редактировать данные. Теперь давайте завершим наш пример и научим приложение записывать сделанные нами изменения обратно в базу данных.
У нас единственным редактируемым полем является описание текущего проекта. Для записи изменений, сделанных в нем, мы воспользуемся методом TableAdapter.Update() для таблицы PROJECT. Добавим элемент Button на нашу форму и в обработчике cсобытия Click напишем следующий код:
private void btnSaveChanges_Click(object sender, EventArgs e) { try { this.pROJECTTableAdapter.Update(this.jobDataSet.PROJECT); MessageBox.Show("Save was successful"); } catch (Exception exception) { MessageBox.Show(exception.Message); } }
Так же неплохо было бы иметь возможность откатить сделанные изменения. Добавим ещё одну кнопку и в обработчике события Click поместим код, который будет отменять все изменения в DataSet, произведенные с момента последнего сохранения:
private void btnUndoChanges_Click(object sender, EventArgs e) { this.jobDataSet.RejectChanges(); //требуется для обновления содержимого TextBox
this.iNTEG36BindingSource.CurrencyManager.Refresh(); }
В процессе написания кода передачи изменений в БД, я столкнулся со следующей проблемой: при редактировании связанных данных через TextBox изменения не передавались в DataSet и метод DataSet.HasChanges() всегда возвращал false. Для решения этой проблемы необходимо в обработчик события TextBox.Validate добавить следующий код:
private void textBox1_Validated(object sender, EventArgs e) { this.iNTEG36BindingSource.EndEdit(); }
Завершенное приложение JobManager доступено в архиве с примерами к статье.
Другие изменения
Новое свойство источника данных «IB Database creation date» позволяет узнать дату создания базы данных. Прочитать его значение можно при помощи класса OleDbProperties, который подробно рассмотрен в разделе «Свойства объектов Ole Db»
Класс TableAdapter
Он является ключевым звеном в цепочке связи данных с пользовательскими элементами управления. Если провести аналогию с терминами М. Фаулера [], то TableAdapter является шлюзом таблицы данных для DataTable. Он инкапсулирует в себе логику обновления загрузки и поиска данных и относится к Data Access Layer. Что же касается DataSet и DataTable, то их можно отнести к уровню бизнес-логики (Business Layer)
Visual Studio .Net 2005 сама позаботилась о генерации кода этого класса. Давайте посмотрим, что же она нам предлагает. Итак:
методы Fill() и GetData() – единственное отличие в том, что Fill принимает существующую DataTable в качестве аргумента, а GetData() создает новую, заполняет её данными и возвращает клиенту.
Свойство ClearBeforeFill, которое используется вышеназванными методами для определения, стоит ли очищать таблицу перед её заполнением.
Стандартный набор CRUD операций: insert, update, delete, среди которых присуствуют перегруженные методы с типизированными аргументами, соответствующими таблице базы данных
Общее свойство Connection
Так же у нас есть возможность создать дополнительные запросы к базе данных. Для этого нам понадобится инструмент Search Criteria Builder. Для его запуска необходимо у нашего адаптера выбрать пункт меню «Add Query»:
Вводим название запроса (а фактически название нового метода в вашем TableAdapte-е), а так же его текст, либо вручную указав условие выборки, либо используя инструмент Query Builder:
ПРИМЕЧАНИЕ.При записи условия выборки используйте позиционные параметры (символ «?»). Код метода будет сгенерирован автоматически, так что особого неудобства это не доставит. |
После всех операций будет сгенерирован соответствующий метод. Так же дизайнер VS .Net 2005 добавит компонент ToolStrip к вашей форме с кнопкой запуска этого метода и полем для задания фильтра. Мне кажется это излишним, но, может быть, кому-нибудь понравится.
СОВЕТ. Visual Studio .Net 2005 разделяет код, используемый дизайнером и пользовательский код за счет partial классов. В нормальном приложении нам наверняка понадобиться расширить логику TableAdapter. Сделать это можно, описав partial class, соответствующий классу конкретного TableAdapter-a, сгенерированного дизайнером. |
Литература
1.обратно | М.Фаулер. Архитектура корпоративных программных приложений. Изд. Москва – Спб – Киев. 2004 г. |
2.обратно | Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. Приемы объектно-ориентированного проектирования. Паттерны проектирования. Изд. Питер. 2006 г. |
3. | А. Ковязин, С.Востриков. Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/Firebird/Yaffil (+ CD-ROM). Изд. КУДИЦ-Образ, Питер. 2005 г. |
4. | Б.Бошемин. Основы ADO .Net. Изд. Вильямс. 2003 г. |
Примеры к статье
Передача изменений обратно в базу данных
После того, как мы изменили данные в DataSet, их необходимо передать обратно в базу. Для этого у объекта OleDbDataAdapter есть метод Update(). Прежде чем его использовать, необходимо настроить наш адаптер. В этом нам поможет класс OleDbCommandBuilder. Он позволяет сгенерировать команды для операций вставки, обновления и удаления, а так же создать соответствующую коллекцию параметров команд. Ниже приведен пример передачи изменений из DataSet в базу данных:
public void UpdateDataSet() { DataSet ds = new DataSet(); DataTable tbl = ds.Tables.Add("EMPLOYEE");
OleDbConnection con = ConnectionProvider.CreateConnection(); con.Open(); OleDbDataAdapter adapter = new OleDbDataAdapter("select * from EMPLOYEE", con); adapter.SelectCommand.Transaction = con.BeginTransaction(); adapter.Fill(tbl);
//вносим изменения в DataSet
foreach (DataRow row in tbl.Rows) row["FIRST_NAME"] = row["FIRST_NAME"].ToString().ToUpper();
//генерируем команды для операций update, insert и delete OleDbCommandBuilder cmd_builder = new OleDbCommandBuilder(adapter); adapter.DeleteCommand = cmd_builder.GetDeleteCommand(); adapter.UpdateCommand = cmd_builder.GetUpdateCommand(); adapter.InsertCommand = cmd_builder.GetInsertCommand();
//обновление данных
adapter.Update(tbl);
//откат сделанных изменений
adapter.SelectCommand.Transaction.Rollback(); con.Close(); }
Передача изменений в базу данных через TableAdapter
Отдельно необходимо остановиться на методах передачи изменений обратно в базу данных. VS .Net 2005 умеет генерировать код запросов для методов insert, update, delete. В некоторых случаях этого может оказаться достаточно, но, как показывает опыт, полученные SQL-выражения пытаются претендовать на универсальность и поэтому не оптимальны, а порой не работоспособны.
Приведу пример: В поставке с Firebird идет база данных employee.fdb. В ней есть таблица SALES. Прежде всего, обращаю внимание на поле AGED, которое доступно только для чтения, т.к. вычисляется с помощью выражения
COMPUTED BY (ship_date - order_date)
Если указать для Select Command текст:
SELECT * FROM SALES
то колонка AGED будет добавлена во все команды обновления. При попытке передать изменения в базу, будет сгенерировано исключение. Необходимо вручную отредактировать текст запросов для insert, update, delete команд и убрать из обновления данную колонку.
Отредактировать SQL выражения можно, вызвав команду «Edit Queries in DataSet designer»:
Откроется дизайнер DataSet, в котором необходимо выбрать нужный TableAdapter (в данном случае это SALESTTableAdapter):
В списке свойств появятся необходимые нам объекты OleDbCommand:
Читатель может подумать, что данный случай - исключение, но это не так. Если вы выберете такой способ создания слоя доступа к данным (Data Access Layer), то будьте готовы постоянно вмешиваться в автоматический процесс генерации SQL запросов.
Встроенные инструменты Visual Studio 2005
Встроенные инструменты Visual Studio 2005 могут оказаться незаменимым подспорьем при написании приложений баз данных. Давайте разберём по шагам создание примера простого приложения JobManager.
Полезные ссылки
Список Ole Db провайдеров различных производителей
Описание Ole Db схем в MSDN
Управляющие последовательности ODBC
Firebird 2 release notes
Firebird SQL Server
Схемы метаданных БД.
Неотъемлемой частью всех Ole Db провайдеров являются схемы метаданных. Они используются клиентами для получения описания базы данных: списка хранимых процедур, структур таблиц, зарегистрированных доменов, ограничений, первичных и внешних ключей и т.д. Для того, чтобы Ole Db провайдер смог работать с библиотекой ADO .Net, он должен поддерживать Ole Db схемы, так как компоненты библиотеки активно используют эту информацию.
По этой ссылке расположен список схем, которые поддерживает IBProvider
Запросить определенную схему можно по её названию. Для этого у объекта OleDbConnection есть метод GetSchema(). В Net 2 появился метод GetOleDbSchema(), который в качестве аргумента принимает одно из значений OleDbSchemaGuid. Оба этих метода ведут себя одинаково и возвращают абсолютно идентичные экземпляры DataTable с набором информации по схеме.
У каждой схемы есть набор колонок, по которым можно отфильтровать возвращаемый результат. Например, в схеме COLUMNS можно наложить ограничения по следующим полям:
Restriction columns: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME. Если мы хотим получить описание всех колонок для таблицы EMPLOYEE, мы должны использовать схему COLUMNS следующим образом:
DataTable schema_table = connection.GetSchema("COLUMNS", new string[] { null, null, "EMPLOYEE" });
Аналогично для метода GetOleDbSchema():
DataTable schema_table = connnection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, "EMPLOYEE" });
Создание каркаса приложения
Создайте новую форму JobForm. Добавьте на форму ComboBox и перейдите в редактор ComboBox Tasks:
Далее необходимо в свойстве Data Source выбрать действие «Add Project Data Source». Откроется мастер создания источников данных:
Выбираем тип источника Database и идем далее. В списке подключений будет уже созданное ранее в Server Explorer подключение:
Делаем все, как показано на рисунке и переходим на следующий шаг:
Мастер предлагает нам сохранить параметры источника данных в файле конфигурации приложения. По умолчанию строка подключения будет сохранена в области «Application Settings» и будет не доступна для редактирования внутри приложения. Это можно изменить, установив для настройки свойство Scope = User. А пока разрешим создание секции в конфигурационном файле и двигаемся далее:
На завершающем шаге нам предлагают создать DataSet. Выберем для него все доступные таблицы базы данных и жмем кнопку «Finish».
Теперь в качестве источника данных для нашего ComboBox выбираем таблицу EMPLOYEE. Свойству DisplayMember установим значение FULL_NAME:
После завершения операции на форму будут добавлены три новых компонента. Это DataSet, TableAdapter и BindingSource. DataSet нам уже знаком, а вот два других объекта появились только в Net 2.0 и будут рассмотрены далее.
Создание подключения в Server Explorer
Выберем команду «Add Connection». Откроется диалог с выбором источника данных. В нем выбираем Data Source = <othrer> и Data provider = .Net Framework Data Provider for OLE DB. Жмем Ok:
Далее появится уже знакомый нам диалог:
Выберите из списка OleDb провайдеров – IBProvider третьей версии. И нажмите кнопку Data Links:
Здесь есть два важных момента: необходимо включить опции «Разрешить автоматические транзакции» и «Разрешить сохранение пароля». Убедимся, что все настроено правильно, нажав на кнопку «Проверить подключение».
Если мы все сделали правильно, в списке подключений Server Explorer появится новое, для которого будет доступен список объектов базы данных:
Специальная поддержка DML (Data Manipulation Language)
Во второй версии Firebird появилось несколько нововведений. Одно из них это инструкция EXECUTE BLOCK. Она позволяет выполнить блок инструкций на стороне сервера, фактически это виртуальная хранимая процедура. Следующий пример демонстрирует использование ресурсов сервера базы данных для выполнения простого арифметического действия:
public void ExecuteBlockSQLTest() { OleDbConnection con = OpenFB2Connection(); OleDbTransaction trans = con.BeginTransaction();
//текст команды
string execute_block_data = "EXECUTE BLOCK (X INTEGER = :X) \n" + "RETURNS (Y INTEGER) \n" + "AS \n" + "BEGIN \n" + " Y = X * 2; \n" + "SUSPEND; \n" + "END \n";
//входящий параметр
int in_parameter_X = 2;
OleDbCommand cmd = new OleDbCommand(execute_block_data, con, trans); cmd.Parameters.AddWithValue("X", in_parameter_X);
//выполнение команды EXECUTE BLOCK
Assert.AreEqual((int)cmd.ExecuteScalar(), in_parameter_X * 2); trans.Commit();
con.Close(); }
Еще одно новшество, которое подарил нам FB2, это инструкция INSERT RETURNING. Фактически она позволяет выполнить операцию вставки данных и прочитать значения, которые были добавлены в процессе этой операции. Это особенно актуально для получения значения идентификатора новой записи, для которого использовался генератор:
public void InsertReturning() { OleDbConnection con = OpenFB2Connection(); OleDbTransaction trans = con.BeginTransaction();
//новая команда INSERT RETURNING OleDbCommand cmd = new OleDbCommand( "insert into customer (cust_no, customer) \n" + "values(GEN_ID(CUST_NO_GEN,1),:customer_name) \n" + "RETURNING cust_no",con,trans);
cmd.Parameters.AddWithValue("customer_name", "New customer"); //добавляем один выходной параметр
cmd.Parameters.Add("customer_no", OleDbType.Integer) .Direction =ParameterDirection.Output;
Assert.AreEqual(1, cmd.ExecuteNonQuery());
//удаляем запись, используя значение генератора, полученного //через INSERT ..
RETURNING
OleDbCommand cmd_delete = new OleDbCommand( "delete from customer where cust_no=?", con, trans);
cmd_delete.Parameters.AddWithValue("?",cmd.Parameters["customer_no"].Value); Assert.AreEqual(1, cmd_delete.ExecuteNonQuery());
trans.Commit(); con.Close(); }
ROLLBACK RETAIN – позволяет откатить транзакцию на момент старта или до последнего вызова COMMIT_RETAIN, оставляя возможность её дальнейшего использования. Давайте рассмотрим это на примере:
public void RollbackRetainTest() { OleDbConnection con = OpenFB2Connection(); OleDbTransaction trans = con.BeginTransaction();
//insert new record OleDbCommand cmd = new OleDbCommand( "insert into customer (cust_no, customer) " + "values(GEN_ID(CUST_NO_GEN,1),'new customer')", con, trans); Assert.AreEqual(1, cmd.ExecuteNonQuery());
//ROLLBACK RETAIN new OleDbCommand("ROLLBACK RETAIN", con, trans).ExecuteNonQuery();
//transaction will be active and we can execute some command again
cmd = new OleDbCommand( "select count(*) from customer", con, trans);
Assert.IsTrue((int)cmd.ExecuteScalar() > 0 );
trans.Commit(); con.Close(); }
Ключевое слово ROWS соответствует последним стандартам ANSI SQL и является альтернативой FIRST/SKIP. Оно позволяет указать количество обрабатываемых записей. Может быть использовано в UNION, любых подзапросах, а так же в командах DELETE и UPDATE. Следующий пример читает из базы данных записи с первой по третью:
public void RowsKeywordTest() { OleDbConnection con = OpenFB2Connection(); OleDbTransaction trans = con.BeginTransaction();
//command will return 3 records
OleDbCommand cmd = new OleDbCommand( "select * from customer rows 1 to 3", con, trans);
short rec_count = 0;
using (OleDbDataReader reader = cmd.ExecuteReader()) while (reader.Read()) { rec_count++; }
Assert.AreEqual(3, rec_count);
trans.Commit(); con.Close(); }
Я привел примеры только некоторых изменений в DML Firebird 2, которые требовали специальной поддержки со стороны Ole Db провайдера.Для изучения полного списка изменений рекомендую вам обратиться к документу: Firebird 2 release notes. Там действительно есть много того, что может заинтересовать разработчиков. Это производные таблицы, новые функции, улучшенный UNION, инструкция NEXT VALUE FOR, поддержка планов для операций обновления и удаления и много чего другого.
Управляющие последовательности ODBC
Управляющие последовательности позволяют преобразовывать текст запроса в процессе выполнения. Последовательность включается в текст запроса в фигурных скобках. Например {fn CURDATE} – выражение будет преобразовано в значение серверного времени.
В ODBC определены управляющие последовательности для следующих характеристик:
Работа со временем и датами
Функции преобразования типов
Предикат LIKE
OUTER JOIN
Вызовы хранимых процедур
Данное расширение активно используется такими инструментами, как MS SQL Server, Crystal Reports, различные OLAP средства и их поддержка со стороны Ole Db провайдера обеспечивает возможность их совместного использования.
Для того, чтобы включить поддержку ODBC расширений в IBProvider, необходимо установить свойство инициализации support_odbc_call = true. По умолчанию поддержка отключена.
IBProvider умеет вызывать хранимые процедуры в ODBC стиле, а также поддерживает следующие функции, которые могут быть использованы внутри управляющих последовательностей:
Функции для работы с датами и временем: CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURDATE, CURTIME, DAYNAME, DAYOFMONTH, DAYOFWEEK, DAYOFYEAR, EXTRACT, HOUR, MINUTE, MONTH, MONTHNAME, NOW, QUARTER, SECOND, WEEK, YEAR.
Конвертирование данных: CONVERT
Системные функции: USER
Строковые функции: UCASE
Следующий пример демонстрирует применение управляющих последовательностей в тексте SQL запросов:
public void ODBCQueriesTest() { OleDbConnectionStringBuilder builder = ConnectionProvider.GetConnectionStringBuilderFromUDL(); builder.Provider = "LCPI.IBProvider.2"; builder.Add("support_odbc_query","true");
OleDbConnection con = new OleDbConnection(builder.ToString()); con.Open(); OleDbTransaction trans = con.BeginTransaction();
//select current day name OleDbCommand cmd = new OleDbCommand( "select " + "{fn dayname({fn now()})} as DAY_NAME," + "{fn dayofweek({fn now()})} as DAY_OF_WEEK," + "{fn dayofmonth({fn now()})} as DAY_OF_MONTH," + "{fn dayofyear({fn now()})} as DAY_OF_YEAR " + "from RDB$DATABASE", con, trans);
using (OleDbDataReader rdr = cmd.ExecuteReader()) if (rdr.Read()) for (int i = 0; i < rdr.FieldCount; i++) Console.WriteLine(rdr.GetName(i) + ": " + rdr[i].ToString());
trans.Commit(); con.Close(); }
На момент написания статьи ODBC запросы поддерживались в 1-й и 2-й версии IBProvider и ещё не были реализованы в третьей. Так что для использования этой возможности необходимо указывать в строке подключения Provider = "LCPI.IBProvider.2"
За более подробной информацией по использованию управляющих последовательностей ODBC советую вам обратиться к документу «ODBC Programmer’s Reference» и изучить раздел «Escape Characters in ODBC».
я рассмотрел наиболее часто используемые
В своем обзоре я рассмотрел наиболее часто используемые возможности библиотеки ADO .Net на примере OLE DB провайдера.
Основное преимущество OLE DB провайдеров перед управляемыми (.Net Data Providers) – это возможность их использования не только в среде .Net Framework, а практически в любых средах, поддерживающих COM.
Использование IBProvider в качестве поставщика данных Firebird позволяет:
Обмениваться данными с приложениями Microsoft Office (включая Access и Outlook)
Использовать VBA (Visual Basic for Applications).
Выгружать данные в 1С и обратно.
Использовать Firebird в качестве связанного сервера MS SQL.
Писать расширенные сценарии автоматизации при помощи WSH (Windows Script Host), VBScript, Java Script
Писать WEB-приложения, WEB-сервисы c базами данных не только на ASP.Net, но и на ASP
Производить анализ данных при помощи различных OLAP средств за счет поддержки ODBC управляющих последовательностей.
Использовать провайдер в составе распределенных транзакций
И ещё много чего.
IBProvider поддерживает все существующие версии Interbase/Yaffil/Firebird. Имеет встроенный менеджер управления памятью и SWAP для пользовательских данных. Поддерживает многопоточность, а так же серверные и клиентские курсоры. Осуществляет многоязыковую поддержку.
Надеюсь, данное руководство позволит вам расширить круг применяемых возможностей ADO .Net не только для работы с Firebird, но и с другими базами данных.
Заполнение объекта DataSet
Класс DataSet служит для хранения данных, загруженных из базы, в памяти. Фактически он представляет собой набор таблиц, связанных отношениями и в идеальном случае копирует структуру исходной базы данных.
Он позволяет существенно сократить количество обращений к базе данных. Это особенно критично для WEB-приложений, для которых частое подключение к базе данных не является оптимальным.
Существуют несколько способов заполнения объекта DataSet:
Первый из них, который появился ещё в Net Framework 1.0, это способ заполнения DataSet при помощи класса OleDbDataAdapter:
public void FillDataSetFromDataAdapter() { DataSet ds = new DataSet();
using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope()) { OleDbConnection con = ConnectionProvider.CreateConnection(); con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("select * from EMPLOYEE", con); adapter.Fill(ds);
Assert.IsTrue(ds.Tables[0].Rows.Count > 0); scope.Complete(); } }
Второй способ появился только в ADO .Net 2.0 – это возможность заполнения DataSet, используя OleDbDataReader:
public void FillDataSetFromDBReaderTest() { OleDbConnection con = ConnectionProvider.CreateConnection(); con.Open(); OleDbCommand cmd = new OleDbCommand("select * from EMPLOYEE",con, con.BeginTransaction());
DataSet ds = new DataSet(); DataTable tbl = ds.Tables.Add("EMPLOYEE");
using (OleDbDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { ds.Load(reader, LoadOption.OverwriteChanges, tbl); } }