В Kylix нет стандартных компонентов для создания многих локальных баз данных.
Связано это с тем, что такие форматы данных являются отмирающими, тем более
что преобразование их в формат XML не вызывает больших затруднений.
Базы данных типа MyBase предоставляют программисту дополнительные возможности.
- Сортировка данных по полям без создания дополнительных файлов индексов.
- Ведение списка изменений и отката сделанных изменений.
- Создание агрегатов на основе данных таблицы.
- Совместное использование одних и тех же данных несколькими наборами данных.
- Совместимость с Delphi 5 и Delphi 6.
Для иллюстрации всего вышесказанного создадим приложение просмотра и редактирования
заказов.
Начнем с создания заготовки приложения. В главном меню Kylix выберем пункт File/New
Application (рис. 18.1).
При этом среда создаст проект с пустой формой Forml. Добавим модуль данных.
Для этого выберем в главном меню Kylix пункт File/New и в открывшемся диалоговом
окне выберем пиктограмму Data Module (рис. 18.2).
Теперь в модуль данных поместим компонент ciientoataSet с вкладки DataAccess.
Установим свойство Name данного компонента в компонент clients. Этот набор данных
будет хранить информацию о заказчиках (рис. 18.3).
Для создания файла базы данных необходимо указать поля и их типы. Сделать это
можно двумя способами:
- определить значение свойства FieldDefs клиентского набора данных;
- создать объекты полей явным образом.
Рис. 18.1. Окно New Items
Рис. 18.2. Пиктограмма Data Module окна New Items
Рис. 18.3. Компонент Clients в окне модуля данных
Создадим поля первым способом. Для этого дважды щелкнем на свойства FieldDefs компонента Clients. При этом откроется диалоговое окно добавления новых полей (рис. 18.4).
Рис. 18.4. Диалоговое окно добавления новых полей
Добавим определения полей, представленные в табл. 18.1.
Таблица 18.1. Определения полей
Имя поля | Описание | Тип данных | Размер |
ID | счетчик | ftAutoInc | 0 |
Name | имя клиента | FtString | 50 |
Рис. 18.5. Установка свойств поля ID в окне Object Inspector
Рис. 18.6. Установка свойств поля в окне Object Inspector
Рис. 18.7. Поля ID и Name
Правой кнопкой мыши щелкнем на компоненте Сlients и выберем в выпадающем меню
пункт CreateDataSet, а затем - пункт Save To MyBase Xml UTF-8 table. В появившемся
диалоговом окне укажем имя xml-файла, который будет хранить данные о клиентах
- Clients.xml и являться главной таблицей нашей базы данных (рис. 18.8).
Для того чтобы при запуске программы клиентский набор данных Clients читал данные
из созданного нами xml-файла, значение его свойства Filename должно быть равно
полному имени xml-файла.
Рис. 18.8. Диалоговое окно сохранения файла таблицы
Теперь определим поля явно на основе FieldDefs. Дважды щелкнем на компоненте Clients, в появившемся диалоговом окне щелчком правой кнопкой мыши откроем контекстное меню и выберем пункт добавления всех полей Add all fields (рис. 18.9).
Рис. 18.9. Поля компонента Clients
Разместим в модуле данных компонент DataSource, установим его свойство Name в ds_Clients и свяжем его с компонентом Clients (свойство DataSet компонента ds_Clients установим равным Clients). Затем установим свойство DataSource в ds_Clients. Окончательный вид модуля данных показан на рис. 18.10.Посмотрим, как устроен внутри файл базы данных xml. После создания набора данных типичный файл базы данных выглядит, как представлено в листинге 18.1.
Рис. 18.10. Модуль данных
Листинг18.1 Содержание типичного файла базы данных
<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="ID" fieldtype="i4" readonly="true"
SUBTYPE="Autoinc"/>
<FIELD attrname="Name" fieldtype="string" WIDTH="50"
/>
</FIELDS>
<PARAMS DEFAULT_ORDER="" AUTOINCVALUE="1" />
</METADATA>
<ROWDATA />
</DATAPACKET>
В первой строке содержится заголовок:
<?xml version="l . О" encoding="UTF-8" standalone="yes"
?>
Вторая строка содержит корневой тэг документа:
<DATAPACKET Version="2.0">
остальную часть файла можно разделить на две части:
- данные о структуре таблицы базы данных, хранимые в файле (метаданные);
- непосредственно записи.
Метаданные хранятся в тэге METADATA, а записи - в тэге ROWDATA. После создания
новой таблицы базы данных тэг ROWDATA будет пустым.
Внутри тэга METADATA расположены описания полей таблицы (тэг FIELDS и вложенные
в него тэги) и другая служебная информация (порядок сортировки по умолчанию,
начальное значение автоматически увеличивающегося счетчика).
Теперь давайте запустим наше приложение, вставим в таблицу новую запись, закроем
приложение и посмотрим, как изменился xml-файл.
Мы видим, что изменился тэг PARAMS:
<PARAMS CHAGE_LOG="1 0 4" AUTOINCVALUE="2" DEFAULT_ORDER>
Кроме того, тэг ROWDATA тоже изменился:
<ROWDATA>
<ROW RowStace="4" ID="1" Name="e?AI?" />
</ROWDATA>
Если вы внимательно посмотрите на изменения, то увидите, что внутри таблицы
ведется журнал операций. Это дает возможность сделать отмену произведенных действий.
Если вам не нужно, чтобы этот журнал велся, в режиме выполнения программы установите
свойство LogChanges в false.
Рассмотрим установку отношений таблиц "главный-подчиненный" (master-detail).
Новым способом организации отношения master-detail в Kylix стало использование
вложенных наборов данных. Предположим, что нам нужно получить информацию о покупках,
сделанных клиентом.
Сначала очистим набор данных Clients. Для этого щелкнем правой кнопкой мыши
на компоненте Clients и в выпадающем меню выберем пункт очистки данных Clear
Data.
Введем дополнительное описание полей Orders типа ftDataSet. Данный тип поля
предназначен для хранения внутри себя наборов данных. Список полей вложенного
набора данных устанавливается в свойстве ChildDef; Определим в ChildDefs следующие
поля (табл. 18.2).
Таблица 18.2. Поля, определяемые в свойстве ChildDefs
Имя поля | Описание | Тип данных | Размер |
ID | счетчик | FtAutoInc | 0 |
OrderName | описание заказа | FtString | 20 |
Price | цена заказа | FtCurrency | 0 |
Осталось только на основе описанных определений создать набор данных (щелкнув правой кнопкой мыши и выбрав пункт выпадающего меню Create DataSet). Затем сохранить в файл (Save to MyBase xml table) и на основе этих определений явным образом создать поля (дважды щелкнув на Clients, затем шелнув правой кнопкой мыши и выбрав пункт Add all fields). Откроем созданный xml-файл (листинг 18.2).
Листинг 18.2. Содержимое файла базы данных
<?xml version=" 1.0" encodinq = "UTF-8" standalone ="yes"?>
- <DATAPACKET Version="2.0">
- <METADATA>
- <FIELDS>
<FIELD attrname="ID" f ieldtype="i4" readonly="true"
SUBTYPE="Autoinc"/>
<FIELD attrname="Name" fieldtype="string" WIDTH="50"
/>
- <FIELD attrname="0rders" fieldtype="nested">
- <FIELDS>
<FIELD attrname="ID" fieldtype="i4" SUBTYPE="Autoinc"
/>
<FIELD attrname="OrderName" fieldtype="string" WIDTH="20"
<FIELD attrname="Price" fieldtype="r8" SUBTYPE="Money"
/>
</FIELDS>
<PARAMS AUTOINCVALUE="1" />
</FIELD>
</FIELDS>
<PARAMS DEFAULT OROER^"" AUTOINCVALUE="1" />
</METADATA>
<ROWDATA />
</DATAPACKET>
Нетрудно убедиться в том, что поле Orders содержит в себе описание подчиненной
таблицы. При этом в сетке данных DBGridi, расположенной на главной форме, появился
новый столбец Orders. При запуске приложения и "попытке редактирования
этого поля автоматически открывается форма для редактирования вложенного набора
данных.
Другим способом организации взаимодействия с вложенным набором данных является
размещение в модуле данных дополнительного клиентского набора данных ClientDataSet.
Поместим в модуль данных еще один компонент типа TdientDataSet, установив его
имя Orders. Свойству SetField компонента Orders из раскрывающегося списка присвоим
значение ClientsOrders. Теперь, пользуясь компонентом Orders, можно просматривать
и редактировать вложенный набор данных.
Достоинства вышеописанного метода в том, что вся база будет храниться в одном
xml-файле, недостаток - в том, что нельзя разорвать связь главный-подчиненный
и, как следствие, одновременно посмотреть все записи о заказах вне зависимости
от выбранного клиента.