Работа с клиентскими наборами данных
В данной части будет рассмотрено применение клиентских наборов данных в dbExpress. Согласно иерархии классов в Kylix к клиентским наборам данных относятся классы TSQLClientDataSet и TClientDataSet. Последний из них является частью технологии MIDAS. Так как на сегодняшний день поддержка данной технологии в Kylix до конца не реализована, то основное внимание мы уделим рассмотрению TSQLClientDataSet. Компоненты класса TSQLClientDataSet предназначены для создания двухзвенных приложений клиент сервер. Так же как и однонаправленные наборы данных, они используются для работы с сервером БД через TSQLConnection. С другой стороны многие из методов и событий класса TSQLClientDataSet характерны для клиентского датасета в технологии MIDAS. На самом деле TSQLClientDataSet - это гибрид, содержащий в себе объекты однонаправленного набора данных, клиентский набор данных и объект провайдера для применения внесенных изменений на сервере БД. "Запихивание под капот" этих объектов позволило существенно упростить разработку двухзвенных приложений баз данных в dbExpress. Простейший проектРабота с TSQLClientDataSet будет проиллюстрирована на примере простой базы данных служащих организации. В качестве сервера БД выбран Interbase 6, т.к он входит в поставку Kylix. Предварительно необходимо создать базу данных с таблицей EMPLOYEERS, описанной следующим образом: /* Table: EMPLOYEERS, Owner: SYSDBA */ CREATE TABLE "EMPLOYEERS" ( "ID" INTEGER NOT NULL, "NAME" VARCHAR(200) NOT NULL, PRIMARY KEY ("ID") ); СREATE GENERATOR "EMP_GEN"; SET TERM ^ ; /* Triggers only will work for SQL triggers */ CREATE TRIGGER "EMPLOYEERS_BEFORE_INS" FOR "EMPLOYEERS" ACTIVE BEFORE INSERT POSITION 0 AS BEGIN NEW.ID = GEN_ID(EMP_GEN,1); END ^ COMMIT WORK ^ SET TERM ;^ Вставим несколько записей в созданную таблицу. Текст запроса на вставку в таблицу выглядит так: Далее запустим IDE Kylix и создадим новое приложение. На главной форме приложения разместим следующие компоненты с закладки dbExpress и установим для них нижеуказанные свойства Двойным кликом мыши вызовем редактор полей. В редакторе полей правой кнопкой мыши вызовем всплывающее меню и в нем выберем пункт Add all fields. При этом поля набора данных будут определены явным образом. Выберем поле ID и установим его свойство Required в false, чтобы снять необходимость ручного ввода значения ID при вставке пользователем новой записи. После этого св-во Connected компонента sc_conn установим в false. ds_src:TDataSource DataSet:scd_emp DBNavigator1:TDBNavigator DataSource - ds_src Align - alTop Panel1:TPanel Align - alBottom Caption - ""(пустая строка) DBGrid1:TDBGrid DataSource - ds_src Align - alTop На Panel1 разместим 4(Button) кнопки c именами b_connect, b_disconnect, b_count, b_fetch (заголовки - Caption - connect, disconnect, get count, fetch all соответсвтенно )и одну надпись (Label). На событие onClick кнопки b_connect навесим обработчик со следующим кодом Sc_conn.Connected:=true; Scd_emp.Active :=true; На событие onClick кнопки b_disconnect навесим обработчик со следующим кодом Sc_conn.Connected:=false; Scd_emp.Active :=false; Назначение размещенных компонентов следующее Запустим на выполнение наш проект, при этом предполагается, что сервер interbase уже запущен. При нажатии кнопки b_connect в сетке данных (DBGrid) можно будет видеть записи таблицы employeers. Навигация по записямМетоды навигации по записям аналогичны однонаправленным наборам данных. Добавление, удаление и редактирование записейДля добавления записей существуют четыре метода
// Использование Append scd_emp.Append; scd_emp.FieldByName('ID').Value:=-1; scd_emp.FieldByName('Name').Value:='Петров'; scd_emp.Post; Определены несколько событий, связанных с вставкой новой записи
Порядок вызова событий
Для удаления текущей записи предназначен метод Delete, события BeforeDelete и AfterDelete генерируются до и после удаления записи соответственно. scd_emp.Delete; Перевод набора данных в режим редактирования осуществляется вызовом метода Edit. При этом проверить доступность редактирования можно, проанализировав свойство CanModify. Еще одним полезным методом является метод CheckBrowseMode. Данный метод автоматически подтверждает или отменяет сделанные изменения перед тем, как будет осуществлен переход на следующую запись в наборе данных. События BeforeEdit и AfterEdit возникают соответственно перед и после редактирования записи. Подтверждение и откат сделанных измененийТак как клиентский набор данных буферизирует сделанные изменения, то применяется двухступенчатое подтверждение сделанных изменений. Первая ступень - это запись сделанных изменений в буфер набора данных, вторая - запись изменений из буфера в сервер БД. Запись изменений в буфер осуществляется вызовом метода Post. События BeforePost и AfterPost генерируются перед и после подтверждения изменений. Многие из компонентов пользовательского интерфейса для работы с данными вызывают метод Post автоматически при переходе на следующую запись набора данных. Отмена записи в буфер набора данных осуществляется вызовом метода Cancel. События BeforeCancel и AfterCancel генерируются перед и после подтверждения изменений. Изменения, сделанные в буфере, SQLClientDataSet хранит в свойстве Delta. Количество изменений хранится в свойстве ChangeCount. Запись сделанных изменений из буфера в БД осуществляется вызовом ApplyUpdates. В качестве параметра функции передается максимальное количество ошибок, допустимых до завершения метода. Функция возвращает количество возникших ошибок. Если в результате применения изменений количество ошибок не превысило заданного, то успешно переданные записи удаляются из свойства Delta (т.е считаются переданными на сервер БД), иначе все записи считаются не переданными. // Передача изменений из буфера в БД if scd_emp.ChargeCount > 0 then if scd_emp.ApplyUpdates(10) > 0 then Application.MessageBox('Обнаружены ошибки'); При вызове ApplyUpdates SQLClientDataSet генерирует набор SQL операторов для передачи каждой вставленной, удаленной и измененной записи в БД. При передаче изменений на сервер БД возникает задача определения соответствия измененной записи из буфера набора данных и записи в БД (т.е формирования части where SQL запроса). Свойство UpdateMode определяет данный критерий. Возможные значения св-ва приведены ниже
Наличие события OnUpdateData позволяет установить параметры обновления для каждой записи, передаваемой на сервер БД. Откат всех сделанных изменений осуществляется с помощью метода CancelUpdates. Данный метод очищает св-во Delta, таким образом, отменяя все изменения в буфере набора данных. Откат последней выполненной операции выполняется вызовом UndoLastChange. Передача True в качестве параметра метода UndoLastChange заставляет курсор перемещаться на откатываемую запись. Но и это еще не все! Можно откатывать назад на произвольное количество операций (здесь под операцией понимается вставка, редактирование, удаление). Для этого существуют так называемые точки сохранения (SavePoint).
Если немного помозговать, то используя точки сохранения, можно организовать не только Undo, но и Redo. Осталось внести некоторые доработки в наш проект, чтобы сделанные изменения были отправлены на сервер БД. Для этого выполним следующие действия: var Form1:Tform1; Id:integer; // Счетчик для поля id, объявленный нами 2. В обработчике события AfterPost scd_emp инициализируем переменную id id:=-1; 3. В обработчике BeforePost scd_emp используем id для заполнения поля id фиктивным значением (реально значение присваивается на сервере). If scd_empID.IsNull then Begin Scd_empID.Value:=id; Dec(id); End; 4. В обработчике события BeforeRefresh scd_emp организуем отправку данных на сервер. if scd_emp.ChangeCount > 0 then if scd_emp.ApplyUpdates(0) > 0 then Abort else id:=-1; Запустим полученное приложение, попробуем вводить или изменять записи - до нажатия кнопки обновления DBNavigator1 все наши изменения не будут отражаться на сервере БД. Закрытие приложения с изменениями, не отправленными на сервер, приводят к потере этих изменений. Обработка ошибокОбработка ошибок также делится на обработку ошибок работы с буфером и обработку ошибок передачи данных на сервер БД. Для обработки ошибок вставки, удаления и редактирования в компоненте TSQLDataSet существуют несколько видов событий
Обработчики вышеперечисленных событий в качестве одного из параметров получают параметр Action типа TDataAction. Изменяя значение этого параметра в обработчике можно варьировать реакцию на произошедшую ошибку. Возможные значения
Клонирование таблицыОписано далее в разделе Работа с локальными базами данных в Kylix. Работа с локальными базами данных в KylixПод локальными мы будем понимать базы данных, файлы которых расположены в файлах на локальном диске компьютера или в локальной сети. Доступ к этим файлам осуществляется приложением напрямую. В Delphi 5, продолжателем которой является Kylix, для работы с локальными базами данных использовалось несколько подходов.
В Kylix разработка компонентов для создания локальных баз данных первого типа отдана на откуп разработчикам сторонних фирм. Связано это прежде всего с тем, что данные форматы данных являются отмирающими, тем более что конвертировние их в формат xml не вызывает больших затруднений. Второй тип баз данных, получивший наименование MyBase, предоставляет дополнительные возможности, такие как
Для иллюстрации всего вышесказанного создадим приложение для просмотра и редактирования заказов. Создание заготовки приложения. Меню File/New Application создаст проект с пустой формой. Добавим модуль данных - File/New. В открывшемся диалоге выбрать пункт DataModule. Создание файла базы данных. В модуль данных поместим компонент ClientDataSet с закладки DataAccess. Св-во Name установим - Clients. Данный датасет будет хранить информацию о заказчиках. Для создания файла базы данных необходимо указать поля и их типы. Сделать это можно двумя способами: Лично я предпочитаю определить FieldDefs, а затем на их основе создать объекты полей :)) Итак, двойной клик на св-ве FieldDefs компонента Clients откроет диалог работы с определениями полей. Добавим следующие определения полей
Правой кнопкой мышки кликнем на Clients и выберем в выпадающем меню пункт CreateDataSet, а затем Save To MyBase Xml UTF-8 table. В появившемся диалоге укажем имя xml файла, который будет хранить данные о клиентах - Clients.xml. Было бы неплохо, чтобы при старте программы ClientDataSet читал данные из созданного нами xml файла. Для этого св-во FileName должно быть равно полному имени (с путем) xml файла. Для Clients это /путь к файлу/Clients.xml. Теперь определим поля явно на основе FieldDefs. Двойной клик на Clients, в диалоге правой кнопкой мыши вызываем контекстное меню, выбираем пункт Add all fields. Затем DataSource - ds_Clients, разместим в модуле данных и свяжем c Clients (св-во DataSet компонента ds_Clients установим равным Clients). Формат xml таблицы БД, откат измененийПосмотрим, как внутри устроен xml файл базы данных. После создания датасета типичный файл БД выглядит так: Строка 1 Так вот всю таблицу можно разделить на две части: данные о структуре таблицы БД, хранимые в файле (метаданные) и собственно сами записи. Как вы уже догадались, метаданные хранятся в теге METADATA, а записи в ROWDATA, естественно что при создании новой таблицы БД тег ROWDATA будет пустым. Внутри тэга METADATA расположены описания полей таблицы (тег FIELDS и вложенные в него теги) и другая служебная информация (порядок сортировки по умолчанию, начальное значение автоинкрементального счетчика). Теперь давайте запустим наше приложение, вставим в таблицу новую запись, закроем приложение и посмотрим как изменился xml файл. Изменился тег PARAMS, теперь он выглядит так: Внимательно посмотрев, на изменения мы увидим, что внутри таблицы ведется журнал операций. Это дает возможность отката сделанных изменений. Подробнее это описано выше для SQLClientDataSet. Добавим, что вызов метода MergeChangeLog делает все изменения, сделанные до его вызова недоступными для отката, т.е очищает журнал действий. Если же Вам совсем не нужно, чтобы журнал велся, в runtime установите св-во LogChanges := false. Обработка ошибок, могущих возникать при описанных действиях аналогична случаю описанному для SQLClientDataSet. Поскольку TClientDataSet держит данные из таблицы в памяти, появилась возможность совместного использования одних данных двумя датасетами. Клонирование осуществляется вызовом метода CloneCursor Параметр Source - источник клонированных данных Первый из способов - это задание св-в MasterSource и MasterFields. Этот способ традиционен еще в Delphi и мы рассматривать его тут не будем - читайте книжки. Новым способом организации отношения master-detail стало использование вложенных датасетов. Вот об этом и пойдет речь. Допустим мы хотим иметь информацию о покупках сделанных клиентом. Сначала очистим датасет Clients - щелкнем правой кнопкой мыши и в контекстном меню выберем - Clear Data. Введем дополнительное FieldDefs Orders - типа ftDataSet. Данный тип поля предназначен для хранения внутри себя датасетов. Набор полей вложенного датасета определяется в свойсвте ChildDefs. Определим в ChildDefs следующие поля
Осталось только создать на основе созданных определений создать датасет (щелкнув правой кнопкой и выбрав Create DataSet), сохранить в файл (Save to MyBase xml table) и на основе этих определений явно создать поля (двойной клик на Clients, правая кнопка мыши - add all fields). Открыв созданный xml файл мы увидим следующее - Нетрудно убедиться в том, что поле Orders содержит в себе описание подчиненной таблицы. При этом в сетке данных DBGrid1, расположенной на главной форме, появился новый столбец Orders. При запуске приложения и попытке редактирования этого поля автоматически открывается форма для редактирования вложенного набора данных. Другим способом организации взаимодействия с вложенным датасетом является размещение в модуле данных дополнительного ClientDataSet. Поместим в модуль данных еще один компонент типа TClientDataSet, установив его имя Orders. Св-ву DataSetField компонента Orders из выпадающего списка присвоим значение ClientsOrders. Все теперь пользуясь компонентом Orders можно просматривать и редактировать вложенный датасет. Достоинства вышеописанного метода в том, что вся база будет храниться в одном xml файле, недостаток же - нельзя разорвать связь главный-подчиненный и как следствие одновременно просмотреть все записи о заказах вне зависимости от выбранного клиента.
Страница сайта http://silicontaiga.ru
Оригинал находится по адресу http://silicontaiga.ru/home.asp?artId=5762 |