Міністерство освіти, науки, молоді і спорту України
Національний технічний університет України
"Київський політехнічний інститут"
BDE ТАADO
ТЕХНОЛОГІЇПРОЕКТУВАННЯ
БАЗ ДАНИХ В DELPHI
МЕТОДИЧНІВКАЗІВКИ
к вивченню та лабораторним роботам здисципліни
"Обчислювальна техніка та програмування"
для студентів напряму
6.051001 - Метрологія та інформаційно-вимірювальні технології
Київ 2012
BDEтаADOтехнології проектування баз даних в Delphi. Методичні вказівки до вивчення та лабораторних робіт з дисципліни " Обчислювальна техніка та програмування" для студентів напряму 6.051001 - Метрологія та інформаційно-вимірювальні технології. / Укл. В.І. Павловський, Д.В. Победа. - Київ: НТУУ "КПІ", 2012.-170 с.
Гриф надано Методичною радою НТУУ "КПІ"
(Протокол № … від ….)
Навчальне видання
BDE ТАADO
ТЕХНОЛОГІЇПРОЕКТУВАННЯ
БАЗ ДАНИХ В DELPHI
МЕТОДИЧНІВКАЗІВКИ
к вивченню та лабораторним роботам здисципліни
"Обчислювальна техніка та програмування"
для студентів напряму
6.051001 - Метрологія та інформаційно-вимірювальні технології
Укладачі: | Павловський Володимир Ілліч, канд. техн. наук, доцент Победа Дарія Володимирівна, асистент |
Відповідальний редактор | В.П. Тарасенко, д-р. техн. наук, проф. |
Рецензент | В.П. Симоненко, д-р. техн. наук, проф. |
Під редакцією викладачів
надруковано з оригінал-макету замовника
ОГЛАВЛЕНИЕ
Стр.
ВВЕДЕНИЕ. 6
1 ВВЕДЕНИЕ В БАЗЫ ДАННЫХ.. 7
1.1 ТИПЫ СУБД.. 7
1.2 СТАНДАРТ ODBC.. 9
1.3 ТЕХНОЛОГИИ ВЗАИМОДЕЙСТВИЯ DELPHI С БД.. 9
1.4 ОСОБЕННОСТИ ТЕХНОЛОГИИ BDE.. 10
1.5 ОСОБЕННОСТИ ТЕХНОЛОГИИ ADO.. 11
1.6 ТАБЛИЦЫ БД И СВЯЗИ МЕЖДУ НИМИ.. 12
1.7 ПЕРВИЧНЫЕ КЛЮЧИ И ИНДЕКСЫ... 12
1.8 ДЕМОНСТРАЦИОННАЯ БД "ПОСТАВЩИК КНИГ". 13
2 ИСПОЛЬЗОВАНИЕ ODBC ДЛЯ ПОДКЛЮЧЕНИЯ ИСТОЧНИКА ДАННЫХ. ВНЕШНИЙ ПСЕВДОНИМ БД.. 15
2.1 СОЗДАНИЕ ВНЕШНЕГО ПСЕВДОНИМА БД.. 15
3 СОЗДАНИЕ ПРОЕКТА С БД В ТЕХНОЛОГИИ BDE. 21
3.1 ОСОБЕННОСТИ ИСПОЛЬЗОВАНИЯ BDE ДЛЯ СОЕДИНЕНИЯ С ИСТОЧНИКОМ ДАННЫХ.. 21
3.2 СТРУКТУРА ПРОЕКТА С БД И ВИЗУАЛЬНЫМИ КОМПОНЕНТАМИ.. 22
3.3 АКТИВИЗАЦИЯ ПРОЕКТА.. 22
3.4 ГЛАВНАЯ ФОРМА ПРОЕКТА.. 23
3.5 МОДУЛЬ ДАННЫХ.. 26
3.5.1 Создание модуля данных TDataModule. 27
3.5.2 Создание компонента TDatabase. 27
3.5.3 Создание компонента TTable. 28
3.5.4 Создание компонента TDataSource. 31
3.5.5 Связь модуля главного окна с модулем данных. 32
3.5.6 Связь сетки TDBGrid и навигатора DBNavigator c источником данных TDataSource. 32
3.5.7 Связь главный-детальный между наборами данных. 33
3.5.8 Задание реляционной связи между наборами данных. 34
3.5.9 Активизация наборов данных. 36
3.5.10.............. Недостатки полученных решений и пути их устранения. 37
3.6 ОБЪЕКТЫ-СТОЛБЦЫ СЕТКИ DBGrid. 37
3.7 ОБЪЕКТЫ-ПОЛЯ НАБОРОВ ДАННЫХ.. 39
3.7.1 Создание объектов-полей. 39
3.7.2 Присоединение к наборам данных новых полей. 41
3.7.3 Присоединение полей из других таблиц. Подстановочные поля. 42
3.7.4 Вычисляемые поля. 43
3.8 ОБРАБОТЧИКИ СОБЫТИЙ КОМПОНЕНТ РАБОТЫ С БД.. 45
3.8.1 Обработчики событий OnGetText полей НД и компонента визуализации данных TDBGrid. 45
3.8.2 Установка системных переменных в обработчике событя OnCreate 46
3.9 БИЗНЕС-ПРАВИЛА И ОБРАБОТЧИКИ СОБЫТИЙ КОМПОНЕНТ РАБОТЫ С БД 47
4 SQL ЗАПРОСЫ К БД.. 51
4.1 КОМПОНЕНТ TQuery. 51
4.2 СОЗДАНИЕ КОМПОНЕНТА TQuery. 52
4.3 ИСПОЛЬЗОВАНИЯ КОМПОНЕНТА TQuery. 54
4.3.1 Свойство SQL. 54
4.3.2 Методы Open и ExecSQL. 56
4.3.3 Схема программного формирования SQL-запроса. 57
4.3.4 Параметрические запросы.. 57
4.3.5 Параметрические запросы и свойство DataSource компонента TQuery 61
4.3.6 Связь главный-детальный с компонентом TQuery в качестве детального набора данных. 63
4.4 ДОСТУП К ПОЛЯМ ЗАПРОСА.. 64
4.4.1 Обращение к значению поля при помощи свойств объектов-полей Value и AsXXXX.. 64
4.4.2 Обращение к значению поля при помощи свойств набора данных Fields и FieldValues. 66
4.4.3 Обращение к значению поля при помощи функции набора данных FieldByName. 66
4.5 ПРОГРАММНЫЙ ДОСТУП К ДАННЫМ ЗАПРОСА.. 67
4.5.1 Общая схема программного доступа к данным запроса. 67
4.5.2 Последовательная навигация по записям. 67
4.6 ОБЗОР СОБЫТИЙ КОМПОНЕНТА TQuery. 69
5 ХРАНИМЫЕ ПРОЦЕДУРЫ И ТРИГГЕРЫ.. 72
5.1 ХРАНИМЫЕ ПРОЦЕДУРЫ... 72
5.2 СОЗДАНИЕ ХРАНИМЫХ ПРОЦЕДУР. 72
5.3 ВЫЗОВ ХРАНИМЫХ ПРОЦЕДУР. 74
5.4 ТРИГГЕРЫ... 76
6 НАБОРЫ ДАННЫХ.. 78
6.1 ОБЗОР СОБЫТИЙ КЛАССА TDBDataSet 78
6.1.1 Реализация каскадных изменений и бизнес-правил. 78
6.1.2 Другие события. 79
7 ТЕХНОЛОГИЯ ADO.. 80
7.1 ОСНОВНЫЕ ОСОБЕННОСТИ ТЕХНОЛОГИИ ADO.. 80
7.2 РЕАЛИЗАЦИЯ ТЕХНОЛОГИИ ADO В Delphi 80
7.3 СОЗДАНИЕ ПРОЕКТА С БД В ТЕХНОЛОГИИ ADO. УСТАНОВКА СВЯЗИ С БД 83
7.3.1 Создание модуля данных. 83
7.3.2 Начало настройки связи. 83
7.3.3 Выбор провайдера. 84
7.3.4 Настройка провайдера. 86
7.3.5 Настройка провайдера Microsoft Jet 4.0 OLE DB Provider 86
7.3.6 Настройка провайдера Microsoft OLE DB Provider for ODBC Drivers 90
7.3.7 Завершение настройки связи. 95
7.3.8 Настройка оставшихся компонент модуля данных. 95
7.4 ОСОБЕННОСТИ ИСПОЛЬЗОВАНИЯ КОМПОНЕНТОВ ADO.. 95
7.4.1 Базовые объекты ADO.. 95
7.4.2 Объект Recordset 96
7.4.3 Объект Command. 96
7.4.4 Объект Parameter 96
7.4.5 Объект Error 97
7.4.6 Объект Field. 97
7.4.7 Объект Property. 97
7.4.8 Связной компонент TADOConnection. 97
7.4.9 Компонент TADOCommand. 98
7.5 СВОЙСТВА, МЕТОДЫ И СОБЫТИЯ ADO КОМПОНЕНТОВ-НАБОРОВ.. 100
7.5.1 Общие свойства с BDE-компонентами. 100
7.5.2 Специфические свойства. 101
7.5.3 Методы класса TCustomADODataSet 103
7.5.4 События класса TCustomADODataSet 104
7.6 КОМПОНЕНТ TADODataSet 106
7.7 КОМПОНЕНТ TADOTable. 106
7.8 КОМПОНЕНТ TADOQuery. 107
8 КОМПОНЕНТЫ ВИЗУАЛИЗАЦИИ ДАННЫХ В Delphi 108
8.1 КОМПОНЕНТ TDBGrid. 108
8.1.1 Свойства. 108
8.1.2 Дополнительные возможности сетки. 109
8.2 КОМПОНЕНТЫ ВИЗУАЛИЗАЦИИ ПОЛЕЙ ТЕКУЩЕЙ ЗАПИСИ.. 110
8.2.1 Компонент TDBText 111
8.2.2 Компонент TDBEdit 111
8.2.3 Компонент TDBCheckBox. 111
8.2.4 Компонент TDBRadioGroup. 112
8.2.5 Списочные компоненты.. 112
8.2.6 Компонент TDBMemo. 113
8.2.7 Компонент TDBRichEdit 114
8.2.8 Компонент TDBCtrlGrid. 114
8.2.9 Компонент TDBNavigator 117
ПРИЛОЖЕНИЕ 2. БД "ПОСТАВЩИК КНИГ". 120
РЕКОМЕНДОВАННАЯ ЛИТЕРАТУРА.. 122
ВВЕДЕНИЕ
Исторически вычислительные машины появились как средство резкого ускорения при проведении сложных расчетов в научной и инженерной деятельности. Однако на сегодня эти задачи перестали быть господствующими при использовании компьютерной техники и составляют по разным оценкам от 3% до 5% общих затрат машинного времени.
На сегодня на передний план вышла способность компьютеров хранить и обеспечивать быстрый доступ и обработку больших объемов данных, что связано с использованием компьютера для моделирования и решения задач в различных предметных (проблемных) областях человеческой деятельности. Компьютерная техника стала центральным звеном систем обработки данных.
Решение задач обработки данных достигается применением определенных средств организации (представления) данных в памяти компьютера, а также созданием специальных средств доступа и обработки этих данных.
Для хранения больших объемов данных в современных компютерных системах используются определенным образом организованные базы данных (БД), а для управления и взаимодействия с БД – системы управления базами данных (СУБД). Следует подчеркнуть, что каждый тип СУБД ориентирован на свой тип БД.
Многие из современных СУБД обладают весьма гибкими и мощными средствами высокоуровневого программирования задач обработки БД. Во многих случаях этих средств достаточно для задач, решаемых конкретными организациями. Вместе с тем возможности таких СУБД резко сокращаются, если необходимо выполнять обработку данных из БД других типов.
С другой стороны современные высокоуровневые языки и среды программирования, ориентированные на обработку данных, обладают мощными средствами по обработке БД разных типов, как локальных, так и распределенных. К таким средам программирования относится и Delphi.
В настоящем пособии на примере БД PostgreSQL, подробно рассматриваются вопросы подключения к программе БД разных типов и средства Delphi по высокоуровневому программированию задач обработки данных.
Еще двумя важными свойствами сред программирования, ориентированных на обработку данных, являются:
1. Возможность создания в этих средах развитых отчетов на основе данных из БД;
2. Обеспечение переносимости.
Этим вопросам посвящено отдельное учебно-методическое пособие "Проектирование баз данных в Delphi. Создание отчетов и распространение пприложений" [1].
ВВЕДЕНИЕ В БАЗЫ ДАННЫХ
Базами данных (БД) называют электронные хранилища информации, доступ к которым осуществляется с одного или нескольких компьютеров. Обычно БД создается для хранения и доступа к данным, содержащим сведения о некоторой предметной области (ПО), то есть некоторой области человеческой деятельности или области реального мира.
ТАБЛИЦЫ БД И СВЯЗИ МЕЖДУ НИМИ
Единицей хранящейся в БД информации является таблица. Каждая таблица представляет собой совокупность строк и столбцов, где строки соответствуют экземпляру объекта, конкретному событию или явлению, а столбцы - атрибутам (признакам, характеристикам, параметрам) этого объекта, события или явления.
Между отдельными таблицами БД могут существовать связи. Такие БД называются реляционными (от relation - связь, отношение). Связанные отношениями таблицы взаимодействуют по принципу главная (master) - детальная (detail).
СОЗДАНИЕ ПРОЕКТА С БД В ТЕХНОЛОГИИ BDE
СТРУКТУРА ПРОЕКТА С БД И ВИЗУАЛЬНЫМИ КОМПОНЕНТАМИ
Общая структура проекта с БД может быть представлена в 2-х вариантах - начальном и расширенном. Оба варианта работоспособны, но расширенный вариант позволяет, в частности, улучшить визуальный интерфейс програмного приложения в соответствии с требованиями конечного пользователя.
Начальный вариант структуры проекта с БД имеет следующий вид
Рисунок 3.2 – Структура проекта с БД и визуальными компонентами
Таким образом, непосредственно в проекте программист должен создать компоненты 3-х типов - наборы данных, источники данных и визуальные компоненты.
АКТИВИЗАЦИЯ ПРОЕКТА
Перед созданием проекта следует создать папку для этого проекта, например Biblioteka, а в ней папку Release и папку Source. В папке Source будут распологаться модули разрабатываемого проекта, а в папке Release работающее приложение.
Начните новый проект. В главном меню выберите Project>Options. В появившемся окне выберите закладку Directories/Conditionals. В поле Output directory укажите путь
"..\Release\"
из папки Sourse к папке Release. Теперь после каждой трансляции исходных модулей проекта результат трансляции в виде работающего приложения будет размещаться в папке Release.
Такое построение проекта создаст дополнительные удобства при переносе приложения.
Рисунок 3.3 – Окно свойства проекта
Связь модуля главного окна с модулем данных
Связь модуля главного окна с модулем данных должна выполняться при активном главном окне. Если вы находитесь в модуле данных или его окне, то перейдите к главному окну программы (щелкните на вкладке fmNaklsU в окне кода и нажмите клавишу F12). С помощью команды File>Use Unit свяжите модуль главного окна fmNaklsU с модулем данных dmNaklsU.
Задание реляционной связи между наборами данных
Находясь в окне модуля даных DM, нажмите клавишу F12 и перейдите в окно кода этого модуля dmNaklsUnit. После этого перейдите на вкладку Diagram в окне кода модуля данных. С помощью мыши "перетащите" компоненты tbNakls и tbMove из окна дерева объектов на вкладку Diagram.
Рисунок 3.19 – Расположение таблиц в окне Data Diagram
Для установления связи между таблицами щелкните на кнопке Master Detail панели инструментов, подведите указатель мыши в виде перечеркнутого круга к нижней кромке верхней таблицы NAKLS (в этот момент указатель превратится в крестик), нажмите левую кнопку мыши и, удерживая ее нажатой, прочертите линию к верхней кромке нижней таблицы MOVEBOOK, после чего отпустите кнопку. На экране появится окно конструктора связей (рисунок 3.20).
Чтобы установить связь между таблицами, нужно указать связываемые поля в родительской и дочерней таблицах. В списке Master Fields щелкните на имени поля NaklID, а в поле Detail Fields щелкните на имени поля MNakl. После чего щелкните на кнопке Add. Эта кнопка станет доступной только после выделения полей связи и перестает быть доступной после щелчка на ней. Закройте окно конструктора связей щелчком на кнопке ОК.
Рисунок 3.20 – Окно конструктора связей
После выполнения этих действий между таблицами NAKLS и MOVEBOOK устанавливается связь один ко многим по полю NaklID, о чем свидетельствует вид окна Data Diagram на рисунке 3.21.
Рисунок 3.21 – Окно Data Diagram после установления связи между таблицами
Теперь, перемещаясь по НД tbNakls, для каждой накладной будет получен соответствующий набор книг из НД tbMove.
Аналогично на вкладку Diagram можно добить другие компоненты типа TTable, например tbBooks, и связать их с уже размещенными компонентами.
Недостатки полученных решений и пути их устранения
Если на этом этапе выполнить прогон программы, то можно увидеть, что сетки связаны друг с другом. При перемещении указателя текущей записи в верхней сетке DBGrid1 автоматически меняется содержимое нижней сетки DBGrid2.
Однако визуально данные использовать практически невозможно, так как:
1. В заголовках колонок сеток DBGrid1 и DBGrid2 указаны наименования соответствующих полей (столбцов) таблиц БД "Поставщик книг", которые имеюют сокращенные наименования на английском языке.
2. Вместо имен партнеров или наименований книг в соответствующих колонках сетки DBGrid1 видны лишь их идентификаторы в таблице NAKLS базы данных, а не их имена в таблицах FIRMS и BOOKS;
Устранить указанные недостатки можно путем использования объектов-столбцов (проект Chapt04\FieldValues\BiblosPrg.dpr).
ОБЪЕКТЫ-ПОЛЯ НАБОРОВ ДАННЫХ
Begin
tbMoveSumma.Value := tbMoveMQuan.Value * tbMoveMPrice.Value;
end;
Чтобы увидеть в сетке DBGrid2 столбец со значениями нового поля MSumma, создайте для него новый объект-столбец - специальный компонент, облегчающих управление отображением данных (см. подраздел 3.5).
ОБРАБОТЧИКИ СОБЫТИЙ КОМПОНЕНТ РАБОТЫ С БД
С компонентами по работе с БД связано большое количество обработчиков событий. Для таких компонент как TDatabase, TTable и TQuery они связаны с бизнес-правилами (бизнес-логикой). Разработка бизнес-правил рассматривается ниже. К таким обработчикам событий, например, относятся AfterDelete или BeforDelete.
Для компонента визуализации данных TDBGrid обработчики событий связаны с заголовками и содержимым объектов-столбцов. К таким обработчикам событий, например, относятся OnGetText или OnSetText.
Ниже рассматривается пример создания обработчика событий OnGetText для компонента визуализации данных TDBGrid.
Begin
Text := tbMoveName.Value + '/' + tbMoveAuthor.Value + '/' +
tbMovePublish.Value;
end;
Установка системных переменных в обработчике событя OnCreate
Во время работы программы можно заметить, что денежные суммы в сетках DBGrid1 и DBGrid2 содержат округленные до гривен значения. Такое отображение денежных сумм, предлагается по умолчанию, что не всегда допустимо.
С другой стороны программе доступны общесистемные переменные, зависящие от локализации Windows, и в том числе - переменная CurrencyDecimals, с помощью которой можно управлять форматом отображения данных типа currency.
Чтобы в денежных полях отображались не только гривны, но и копейки, создайте такой обработчик события OnCreate главной формы программы:
procedure TFinNakls.FormCreate (Sender: TObject);
Begin
//Задается показ типа данных currency с двумя знаками после запятой
CurrencyDecimals := 2
end;
Begin
while nottbMove.EOF do// Пока в списке книг есть хотя бы
tbMove.Delete // одна книга, удаляем ее
end;
Следует подчеркнуть, что в обработчике учитывается то обстоятельство, что НД tbMove связан с текущей записью НД tbNakls отношением многие к одному и, следовательно, содержит данные только по тем книгам, которые относятся к удаляемой накладной.
Аналогичным образом с помощью обработчика BeforeDelete набора данных tbMove реализуются бизнес-правила, связанные с удалением информации о книге из списка книг.
Примечание. Следует подчеркнуть, что хранение значений полей таблиц в разных типах БД реализуется по-разному (см. раздел 4). Поэтому для их обработки в Delphi необходимо явно указать, в каком виде представлять эти значения. Например, вражение
tbNaklsNSum.AsFloat
требует представления объекта-поля tbNaklsNSum как числа типа Float, что при вычислениях в Delphi эквивалентно real.
Более точный код обработчика tbNaklsBeforeDelete приведен ниже (проект Chapt04\FieldValues\BiblosPrg.dpr).
Type
TDM = class (TDataModule)
DB: TDatabase; //База данных
tbNakls: TTable; //Наборы данных
tbMove: TTable;
tbFirms: TTable;
tbBooks: TTable;
tbTypeNakl: TTable;
DataSource1: TDataSource; //Источники данных
DataSource2: TDataSource;
tbNaklsNaklId: TAutoIncField; //Объекты-поля
tbNaklsNSum: TFloatField;
tbNaklsNPayedSum: TFloatField;
…
tbMoveMoveID: TAutoIncField;
tbMoveMNakl: TIntegerField;
…
tbFirmsFirmID: TAutoIncField;
tbFirmsFName: TStringField;
tbFirmsFFinDelta: TFloatField;
tbFirmsFChgDelta: TFloatField;
…
tbBooksBookID: TAutoIncField;
tbBooksBName: TStringField;
…
tbTypeNaklTypeID: TSmallintField;
tbTypeNaklTName: TStringField;
procedure tbMoveNameGetText(Sender: TField; var Text: string;
DisplayText: boolean);
procedure tbNaklsBeforeDelete(DataSet: TDataSet);
procedure tbMoveBeforeDelete(DataSet: TDataSet);
private
{ Private declarations }
IsNaklDel: boolean; //содержит True, если удаляется накладная
public
{ Public declarations }
end;
Var
DM: TDM; //Модуль данных
Implementation
procedure TDM.tbNaklsBeforeDelete(DataSet: TDataSet);
Begin
//Изменяем финансовое или обменное сальдо партнера
//в соответствии с типом накладной:
tbFirms.Edit; //Редактируем НД tbFirms
case tbNaklsNType.AsInteger of
0,3,6: tbFirmsFFinDelta.AsFloat := tbFirmsFFinDelta.AsFloat +
tbNaklsNSum.AsFloat;
4: tbFirmsFChgDelta.AsFloat := tbFirmsFChgDelta.AsFloat +
tbNaklsNSum.AsFloat;
5: tbFirmsFChgDelta.AsFloat := tbFirmsFChgDelta.AsFloat –
tbNaklsNSum.AsFloat;
else tbFirmsFFinDelta.AsFloat := tbFirmsFFinDelta.AsFloat –
tbNaklsNSum.AsFloat;
end;
tbFirms.Post; //Запоминаем сделанные изменения в НД Firms
IsNaklDel := True; //Блокируем часть действий обработчика tbMoveBeforeDelete (описание переменной IsNaklDel см. выше - в секции Private класса TDM)
whilenot tbMove.EOF do //Пока в списке книг есть хотя бы одна книга,
//удаляем ее
tbMove.Delete; //Удаление текущей записи (книги) в НД tbMove
//Восстанавливаем работу обработчика tbMoveBeforeDelete
IsNaklDel := False;
end;
Полный код обработчика MoveBeforeDelete приведен ниже
procedure TDM.tbMoveBeforeDelete(DataSet: TDataSet);
Var
Sum: real;
Begin
tbBooks.Edit; //Редактируем НД tbBooks
//Изменяем количество книг на складе с учетом типа накладной:
//если по накладной были получены книги, из общего количества
//книг на складе вычитаем количество книг в удаляемой записи,
//в противном случае - прибавляем
case tbNaklsNType.AsInteger of
0,3,4,6: tbBooksBQuan.Value := tbBooksBQuan.Value - tbMoveMQuan.Value;
else
tbBooksBQuan.Value := tbBooksBQuan.Value + tbMoveMQuan.Value;
end;
tbBooks.Post; //Запоминаем изменения НД tbBooks
//Если обработчик активизирован при удалении накладной, его работу
//нужно завершить, в противном случае (при удалении записи в сетке
// DBGrid2) следует изменить сальдо партнера и сумму в накладной
if IsNaklDel then Exit; //Активизация при удалении накладной?
//-Да. Завершаем работу
Sum := tbMoveMQuan.AsInteger * tbMoveMPrice.AsFloat;
//Изменяем финансовое или обменное сальдо партнера
tbFirms.Edit; //Редактируем НД Firms
case tbNaklsNType.AsInteger of
0,3,6: tbFirmsFFinDelta.AsFloat := tbFirmsFFinDelta.AsFloat + Sum;
4: tbFirmsFChgDelta.AsFloat := tbFirmsFChgDelta.AsFloat + Sum;
5: tbFirmsFChgDelta.AsFloat := tbFirmsFChgDelta.AsFloat - Sum;
else tbFirmsFFinDelta.AsFloat := tbFirmsFFinDelta.AsFloat - Sum;
end;
tbFirms.Post; //Запоминаем изменения в НД Firms
//Изменяем сумму в накладной
tbNakls.Edit; //Редактируем НД tbNakls
tbNaklsNSum.AsFloat := tbNaklsNSum.AsFloat - Sum;
tbNakls.Post; //Запоминаем изменения в НД tbNakls
end;
КОМПОНЕНТ TQuery
Компонент TQuery порожден от родительского класса TDBDataSet, рассмотренного в разделе 5, и наследует от него основные методы, события и свойства.
Таким образом, компонент TQuery может рассматриваться как эквивалент компонента TTable, который отличается только тем, что его состав определяется содержимым запроса и располагается в локальной таблице. Следовательно, процесс создания в модуле данных компонента TQuery и организация его связи с компонентом TDataSource остается такой же, как и у компонента TTable. Ниже показан процесс подключения компонента TQuery к проекту.
Так же как и компонент TTable компонент TQuery имеет собственные свойства, методы и события, наиболее важные из которых рассматриваются в этом разделе.
ИСПОЛЬЗОВАНИЯ КОМПОНЕНТА TQuery
Схема программного формирования SQL-запроса
Ниже приводится традиционная схема программного формирования и активизации SQL-запроса. Она состоит в следующих шагах:
1. Закрытие текущего запроса, если ранее он был открыт на этапе проектирования или выполнения программы;
2. Очистка текста – свойства SQL, текущего запроса;
3. Формирование нового текста SQL-запроса;
4. Заненсение текста SQL-запроса в свойство SQL компонента TQuery;
5. Открытие или активизация запроса;
6. В случае результативного выполнения запроса Select выполняется переход к первой записи временной таблицы, содержащей результат запроса.
Ниже приводится соответствующий фрагмент текста программы. При этом компонент quNakls расположен на главной форме.
var SQLTxt: string;
…
Begin
quNakls.Close; // Закрытие запроса
quNakls.SQL.Clear; // Очистка запроса
// Формирование нового текста запроса
SQLTxt := 'SELECT NaklID, NDate, FName, TName, NSum, NFirm, ' +
'NPayedSum, NRetSum, NCoeff, NretDate ' +
'FROM Nakls, Firms, TypeNakl ' +
'WHERE FirmID = NFirm AND TypeID = NType AND ' +
'NSum > 10000 AND NType IN (0, 6) AND ' +
'NDate = "02.03.2000" ';
quNakls.SQL.Add(SQLTxt); //Занесение нового текста запроса в свойство SQL
quNakls.Open; // Открытие запроса
quNakls.First; //Переход к первой записи результата запроса
end;
Begin
quNakls.Close; // Закрытие запроса
quNakls.SQL.Clear; // Очистка запроса
// Формирование нового текста запроса
TmpTxt := '02.03.2000';
SQLTxt := 'SELECT NaklID, NDate, FName, TName, NSum, NFirm, ' +
'NPayedSum, NRetSum, NCoeff, NretDate ' +
'FROM Nakls, Firms, TypeNakl ' +
'WHERE FirmID = NFirm AND TypeID = NType AND ' +
'NSum > 10000 AND NType IN (0, 6) AND ' +
'NDate = ' + TmpTxt;
//'NDate = ' + Edit1.txt;
quNakls.SQL.Add(SQLTxt); //Занесение нового текста запроса в свойство SQL
quNakls.Open; // Открытие запроса
quNakls.First; //Переход к первой записи результата запроса
end;
Однако такое решение не всегда удобно. Поэтому в современных языках программирования в SQL-запросах применена техника подобная процедурам с параметрами, когда SQL-запрос уточняется с помощью набора параметров.
Значения параметров могут меняться в процессе прогона программы и, в общем случае, порождают одинаковые по структуре, но разные по содержанию НД.
В тексте параметрического запроса компонента TQuery имени параметра предшествует двоеточие ":". Количество параметров не ограничено.
Пусть, например, нужно создать запрос, который во время выполнения программы возвращает НД со списком партнеров, поставивших книги в определенный день, который указывается в параметре DATA. В этом случае вместо статического запроса, показанного выше, следует использовать параметрический запрос. В тексте параметрического запроса имени параметра DATE предшествует двоеточие ":".
Рисунок 4.8 – Текст параметрического запроса в окне редактора кода
Начальное значение параметра DATE может быть задано на этапе разработки программы и изменено в процессе ее выполнения.
Для установки начального значения параметра DATE необходимо вызвать редактор свойства Params запроса (рисунок 4.9)
Рисунок 4.9 – Вызов редактора свойства Params
В результате появится окно редактора, содержащее заготовку для создаваемого параметра DATE. Первый по счету параметр имеет индекс 0.
Рисунок 4.10 – Содержимое редактора свойства Params
Теперь необходимо выполнить редактирование параметра DATE с помощью инспетора объектов дя этого параметра. Для этого необходимо щелкнуть мышью на DATE после чего появятся свойства параметра (рисунок 7.11)
Рисунок 4.11 – Определение начального значения параметра DATE
Имена параметров могут быть произвольными идентификаторами Delphi. Регистр букв в них не имеет значения. Для задания начального значения параметра обычно достаточно в окне инспектора объектов определить его свойство Value, тогда Delphi автоматически укажет его тип данных в свойстве DataType. Если тип указан неверно (например, вместо integer среда Delphi выбрала SmallInt), следует раскрыть список этого свойства и выбрать тип данных явно. Не следует менять имя параметра в свойстве Name на другое, так как в этом случае Delphi не корректирует текст запроса и в нем будет фигурировать прежнее имя.
Для программного задания значения параметра (см. ниже) используется свойство компонента TQuery:
propertyParams[Index: word]: TParams;
Можно также использовать следующий метод компонента TQuery:
functionParamByName(constValue: string): TParam;
В первом случае конкретный параметр задается индексом Index, причем первый по тексту запроса параметр имеет индекс 0, второй - 1 и т. д. Во втором случае параметр определяется своим именем в тексте запроса (но не именем в свойстве Name инспектора объектов!). В любом случае при обращении к параметру его значение нужно явно приводить к типу данных параметра свойством AsXXXX:
quNakls.Params[0].AsDate := '02.03.2000';
quNakls.ParamByName('Date').AsDate := '02.03.2000';
Если к моменту программного изменения параметра запрос был открыт, его нужно закрыть, установить параметр(ы) и открыть вновь. Например:
quNakls.Close; // Закрытие запроса
quNakls.SQL.Clear; // Очистка запроса
// Формирование нового текста запроса
SQLTxt := 'SELECT NaklID, NDate, FName, TName, NSum, NFirm, ' +
'NPayedSum, NRetSum, NCoeff, NretDate ' +
'FROM Nakls, Firms, TypeNakl ' +
'WHERE FirmID = NFirm AND TypeID = NType AND ' +
'NSum > 10000 AND NType IN (0, 6) AND ' +
'NDate = :Date' ;
quNakls.SQL.Add(SQLTxt); //Занесение нового текста запроса в свойство SQL
//Параметры запроса записываются после занесения нового
//запроса
quNakls.Params[0].AsDate := 02.03.2000;
//quNakls.ParamByName('Date').AsDate := '02.03.2000';
quNakls.Open; // Открытие запроса
quNakls.First; //Переход к первой записи результата запроса
Примечание. Параметры запроса записываются после занесения нового запроса.
Значение NULL свидетельствует о том, что полю не присвоено никакого значения ("пустое" поле). Значение 0 для числовых полей или пустая строка для текстовых полей - это вполне определенные, отличные от NULL значения. Чтобы присвоить параметру значение NULL при прогоне программы, следует выполнить его метод Clear (на этапе разработки нужно очистить свойство Value параметра в окне инспектора объектов). Например:
quNakls.Params[0].Clear;
ПРОГРАММНЫЙ ДОСТУП К ДАННЫМ ЗАПРОСА
Для просмотра, вставки, редактирования и удаления записей в Delphi обычно используются соответствующие визуальные компоненты (TDBGrid, TDBEdit, TDBNavigator и т.д.), которые автоматически вызывают нужные методы НД.
Однако во многих случаях, необходим программный доступ к информации без использования визуальных компонент доступа к данным.
Программный доступ тесно связан с понятием курсора НД. Под курсором НД понимается указатель текущей записи в конкретном НД - таблице или запросе.
Текущая запись - это та запись, над которой в данный момент времени можно выполнять какие-либо операции, например, чтение значений, содержащихся в полях записи.
С помощью методов First, Last, Next, Prior, MoveBy, FindFirst, FindLast, FindNext, FindPrior можно изменять положение курсора и, следовательно, выбирать нужную запись в таблице или запросе.
Общая схема программного доступа к данным запроса
При программном доступе к данным, прежде всего, необходимо открыть соответствующий НД, для чего используется метод Open.
Во многих случаях (см. примеры ниже) после этого нужно убедиться в том, что НД содержит записи. Для этого вызывается метод IsEmpty, который возвращает false, если в НД есть хотя бы одна запись, например
if not quBooks.IsEmpty then …
Если НД не пустой, курсор НД устанавливается на 1-ой записи этого НД и она может быть обработана.
После обработки текущей записи переход к следующей записи реализуется методом FindNext или Next. В следующем разделе подробно рассматриваются другие средства навигации по НД.
По окончанию обработки НД должен быть закрыт.
Repeat
//Какие-либо действия над очередной записью
until notquBooks.FindNext; // Переход к следующей записи
…
quBooks.Close;
Если же от момента открытия НД с ним уже проводились некоторыые действия и программист хочет задать начало очередной обработки с 1-ой или последней записи, то это можно реализовать следующим образом.
Пусть стартовой будет 1-ая запись набора.
quBooks.First;
while not quBooks.EOF do begin
//Какие-либо действия над очередной записью
quBooks.Next;
end;{while}
или
ifnotquBooks.IsEmpty then // проверка набора на непустоту
Begin
quBooks.First;
Repeat
{Какие-либо действия над очередной записью}
until notquBooks.FindNext;
end; {with}
Точно так же можно перемещаться от конца НД к его началу. Пусть стартовой будет последняя запись набора.
quBooks.Last;
while not quBooks.BOF do begin
{Какие-либо действия над очередной записью}
quBooks.Prior;
end;{while}
или
ifnotquBooks.IsEmpty then // проверка набора на непустоту
Begin
quBooks.Last;
Repeat
{Какие-либо действия над очередной записью}
until not quBooks.FindPrior;
Если НД допускает вызов записи по ее номеру (его свойство IsSequenced в этом случае должно содержать значение True), можно использовать цикл for. Например, следующий обработчик события TForm.OnActivate поместит все значения строкового поля BName НД tbBooks в многострочное текстовое поле Memo1:
Var
RecNo: integer;
Begin
…
ifquBooks.IsSequenced then
forRecNo := 1 toquBooks.RecordCount do begin
{Какие-либо действия над очередной записью)
end;
…
Свойство RecNo определяет порядковый номер обрабатываемой записи НД (нумерация начинается с 1), а его свойство RecordCount - количество записей.
Примечание. Во всех случаях следует помнить, что, если в ходе выполнения цикла последовательного перебора записей, изменится ключевое поле записи или в НД будет вставлена новая (удалена старая) запись, курсор НД может изменить свое положение и правильная работа цикла будет нарушена (см. ниже).
ХРАНИМЫЕ ПРОЦЕДУРЫ И ТРИГГЕРЫ
Begin
<Оператор1>
…
<Операторn>
End
Операторы исполнительной части подобны операторам других языков программирования.
Пример. Процедура имеет ряд входных параметров и не возвращает параметров:
CREATE PROCEDURE InsNakl (pname varchar(20), pauthor varchar(20), …)
As
Begin
INSERT BName, BAuthor, … INTO Nakls VALUES (:pname, :pauthor, …)
End
Специальный интерес представляет оператор SELECT. Различают 2-а вида оператора SELECT.
Оператор выбора одной строки SELECT, который возвращает одну строку. Значение столбцов возвращаемой строки присваиваются указанным переменным или параметрам.
Пример. Процедура возвращает одну строку из двух параметров:
CREATE PROCEDURE Payed
returns (psum float, pavg float) /*Выходные параметры*/
As
Begin
SELECT sum(NSum), avg(NSum)
FROM Nakls
INTO :psum, :pavg; /*Запись в параметры*/
End
Оператор выбора нескольких строк FOR SELECT … DO, способный возвращать несколько строк:
for <Оператор выбора строки> do <Оператор>;
Пример. Обработка возвращаемых строк выполняется внутри процедуры. Но из процедуры строки не возвращаются:
CREATE PROCEDURE CountNakl
returns (psum integer)
As
declare variable n integer;
declare variable x integer;
Begin
x = 0;
for SELECT NaklID FROM Nakls INTO :n do
x = x + 1;
:psum = x;
End
End
Для того, что бы процедура вернула строки, полученные с помощью оператора for select do после слова do указывается оператор suspend возврата значений, который передает в вызывающее приложение или хранимую процедуру значения выходных параметров.
Пример: Процедура возвращает строки.
CREATE PROCEDURE books (ppublish varchar(20))
returns (pname varchar(20), pauthor varchar(20))
As
Begin
for SELECT BName, BAuthor
FROM Books
WHERE BPablish= : ppublish
INTO :pname; :pauthor
do suspend;
End
Ключевым в работе процедуры является указание suspend. В тот момент, когда выполнение процедуры доходит до suspend, сервер останавливает выполнение процедуры, и ожидает, пока клиент не запопросит получение данных из процедуры. После получения данных (одной строки) сервер прокрутит следующий цикл for select do до очередного suspend, и так далее, пока клиент не перестанет запрашивать строки, или пока строки в запросе не кончатся.
Из процедуры можно вызвать так же другую процедуру при помощи оператора execute procedure:
execute procedure <Имя процедуры> [(<Список входных параметров>)]
[returning_values (<Список выходных параметров>)]
Пример:
CREATE PROCEDURE ptest
returns (opresult float)
As
Begin
execute procedure pdivide (100, 20) returning_values (opresult);
End
Хранимую процедуру можно удалить оператором
DROP PROCEDURE <Имя процедуры>
Изменяется хранимая процедура оператором
ALTER PROCEDURE <Имя процедуры>
ВЫЗОВ ХРАНИМЫХ ПРОЦЕДУР
Если хранимая процедура выполняет действие, но не возвращает значений или возвращает 1-ну строку
Если хранимая процедура выполняет действие, но не возвращает значений или возвращает 1-ну строку, то можно использовать:
ü компонент TStoredProc;
ü компонент TQuery.
Рассмотрим, для примера, процедуру, которая выполняет оператор Insert.
Примечание. В действительности для вставки записи использовать хранимую процедуру не стоит, ведь процедуры предполагают определенную функциональную обработку. Но это хороший пример процедуры, которая не возвращает значений.
Пример вызова хранимой процедуры с помощью компонента TStoredProc:
DB.StartTransaction; //старт транзакции
with StoredProc1 do
Try
StoredProcName := 'InsNakl';
//Подготовка параметров
Prepare;
ParamByName('pname').AsString := Edit1.Text;
ParamByName('pauthor').AsString := Edit2.Text;
…
ExecProc;
Close;
DB.Commit; //если все хорошо
Except
DB.Rollback; //если ошибка
end;
Пример вызова хранимой процедуры с помощью компонента TQuery:
DB.StartTransaction; //старт транзакции
with Query1. do
begin
SQL.Clear;
//Вызов хранимой процедуры InsNakl с несколькими параметрами
SQL.Add('EXECUTE PROCEDURE InsNakl (:pname, :pauthor, …)');
//занесение параметров
ParamByName('pname').AsString := Edit1.Text;
ParamByName('pauthor').AsString := Edit2.Text;
…
try
ExecSql;
Close;
DB.Commit; //если все хорошо
Except
DB.Rollback; //если ошибка
end;
Если хранимая процедура возвращает несколько строк
Если хранимая процедура возвращает несколько строк, то можно использовать только компонент TQuery. Например, для процедуры Books получим:
DB.StartTransaction; //старт транзакции
with Query1. do
begin
SQL.Clear;
//Вызов хранимой процедуры Books с 1-м входным параметром
SQL.Add('SELECT * FROM Books(:ppublish)');
//занесение параметров
ParamByName('ppublish').asString := Edit1.Text;
try
ExecSql;
Close;
DB.Commit; //если все хорошо
Except
DB.Rollback; //если ошибка
end;
Примечание. Следует подчеркнуть, что в операторе SELECT список параметров задается символом "*".
К соответствующему полю результата запроса, содержащего хранимую процедуру, возвращающую значения, можно обратиться по его порядковому номеру, например,
Query1.Fields[0].AsString;
StoredProc1.Fields[0].AsString
или по имени, если вы его знаете, например
Query1.FieldByName('pname').asString;
StoredProc1.FieldByName('pname').asString;
End
Отметим, что для доступа к значениям столбца используются конструкции формата:
old.<Имя столбца> /*Обращение к старому значению*/
new.<Имя столбца> /*Обращение к новому значению*/
НАБОРЫ ДАННЫХ
Под набором данных (НД) понимается группа записей из одной или нескольких таблиц физической БД, доступная для компонент-наборов TTable, TQuery или TStoredProc. Указанные компоненты порождены от общего родительского класса TDBDataSet, который рассматривается в этом разделе.
Все излагаемые в этом разделе сведения в равной степени относятся к любому из указанных компонент-наборов - TTable или TQuery, и составляют основу организации программного доступа к данным этих компонент.
Кроме того компоненты TTable или TQuery TStoredProc имеют свои методы и свойства, направленные на повышение гибкости проектирования программ и программной обработки данных.
Примечание. Следует подчеркнуть, что родительскому классу TDBDataSet не сопоставляется компонент и поэтому он не имеет графического изображения. Однако этот класс доступен в программе, а его методы являются основой доступа к данным в НД.
ОБЗОР СОБЫТИЙ КЛАССА TDBDataSet
Все НД получают в свое распоряжение большое количество событий, унаследованных ими от родительского класса TDBDataSet. Ниже рассматриваются наиболее важные из них.
ТЕХНОЛОГИЯ ADO
СОЗДАНИЕ ПРОЕКТА С БД В ТЕХНОЛОГИИ ADO. УСТАНОВКА СВЯЗИ С БД
В этом разделе рассматриваются основные особенности использования технологии ADO. Описанный далее пример повторяет пример, рассмотренный в разделах 2, 3 и 4.
Процесс создания проекта можно представить в виде последовательности из 6-ти шагов.
Создание модуля данных
Начните новый проект и добавьте к нему модуль данных или создайте копию уже существующего проекта с BDE.
В случае нового проекта поместите в модуль данных компонент ADOConnetion, 5 компонентов ADOTable (вкладка ADO палитры компонентов) и два компонента DataSource (вкладка Data Access).
Назовите таблицы ADOTable именами tbNakls, tbMove, tbFirms, tbBooks, tbTypeN и свяжите источник данных DataSource1 с таблицей tbNakls, а источник данных DataSource2 - с таблицей tbMove (рисунок 11.2).
В случае существующего проекта с BDE замените в модуле данных компонент TDataBase на компонент ADOConnetion, а 5 компонентов TTable на 5 компонентов ADOTable.
Результирующий вид модуля данных приведен на рисунке 10.2.
Рисунок 7.2 – Модуль данных и дерево объектов
Настройка провайдера
Поскольку большинство параметров связи зависят от провайдера, содержимое 3-х других вкладок панели настройки связи также определяется этим фактором.
Сначала опишем содержимое вкладок при выборе провайдера Microsoft Jet 4.0 OLE DB Provider, а затем содержимое этих вкладок при выборе провайдера Microsoft OLE DB Provider for ODBC driver.
Завершение настройки связи
Щелкните (рисунок 10.3) на кнопке ОК. Связь готова. Чтобы в дальнейшем связь с БД устанавливалась без открытия промежуточного диалогового окна с запросом имени пользователя и пароля, поместите в свойство LoginPrompt компонента ADOConnection1 значение False.
ОСОБЕННОСТИ ИСПОЛЬЗОВАНИЯ КОМПОНЕНТОВ ADO
Базовые объекты ADO
MS ADO имеет 7-мь базовых объектов: Connection, Recordset, Command, Parameter, Field Error и Property.
Компоненты ADO в палитре компонентов Delphi представляют собой надстройки над базовыми объектами, представляя большинство их свойств методов и событий в привычном для Delphi виде.
Объект Connection
Объект Connection в первую очередь предназначен для установления соединения с данными. Кроме того, этот объект обеспечивает механизм транзакций. На него может ссылаться произвольное количество объектов Command и Recordset. В этом случае объект Connection управляет транзакциями этих объектов. С объектом Connection связан набор объектов Error, в котором фиксируются все ошибки, связанные с работой объекта Connection.
Объект Recordset
Объект Recordset представляет собой текущий НД. Он может быть получен только после выполнения метода Execute какого-либо объекта Command. С объектом Recordset автоматически связывается набор объектов Field, в которых описываются все поля НД. Объект Recordset способен хранить нужные записи, перемещаться по ним, добавлять, удалять и редактировать записи как в обычном (при одновременном изменении физических таблиц БД), так и в пакетном режиме (то есть при кэшировании данных). При создании объекта Recordset автоматически создается и связанный с ним курсор, обеспечивающий просмотр, редактирование и изменение записей.
Объект Command
С помощью объекта Command пользователь может выполнить над данными любую SQL-команду. С ним может быть связан набор объектов Parameter, в котором описываются соответствующие параметры, необходимые для выполнения запроса. Характерной особенностью объекта Command является возможность асинхронного выполнения связанной с ним команды. При обнаружении ошибки с объектом Command связывается своя коллекция объектов Error.
Примечание. Объекту Command соответствуют целых 4 компонента Delphi: TADOCommand, TADOTable, TADOQuery и TADOStoredProc. Сделано это, судя по всему, в целях унификации с компонентами вкладки BDE, хотя возможности TADOCommand во многом подобны возможностям TADOTable, и наоборот.
Объект Parameter
Объект Parameter определяет единственный параметр, который будет использоваться при выполнении метода Execute объекта Command. Для этого параметра устанавливается тип, размер и способ применения (входной, выходной, входной и выходной или только для чтения). При необходимости с объектом Command можно связать коллекцию объектов Parameter для указания множества параметров.
Объект Error
Коллекция объектов Error хранит все ошибки, связанные с работой остальных объектов, и прежде всего объектов Connection, Command и Recordset.
Объект Field
Объект Field хранит всю необходимую информацию об одном поле НД. Поскольку обычно НД содержит несколько полей, с объектом Recordset связана коллекция объектов Field. С любым полем Field можно связать произвольную коллекцию объектов Property, определяющих индивидуальные характеристики поля.
Объект Property
Объект Property может быть связан с любым другим объектом ADO, кроме объектов Connection и Error. Он может хранить как статические, так и динамические свойства. Статических (то есть заранее заданных) свойств у объекта всего четыре: Name, Type, Value, Attributes. Остальные свойства динамические и создаются в ходе выполнения программы. В объекте Property задаются некоторые индивидуальные характеристики связанного с ним объекта ADO.
Var
i: integer;
Begin
fori := 0 to(ADOConnection1.DataSetCount - 1) do
ADOConnection1.DataSets[i].Open;
end;
С помощью методов GetProcedureNames и GetTableNames можно получить список всех хранимых процедур и таблиц. Например:
ADOConnection1.Open;
ADOConnection1.GetTableNames(ListBox1.Items)
Важной особенностью компонента является возможность управления с его помощью транзакциями. Для этого в состав компонента добавлены соответствующие методы и события.
С помощью метода BeginTrans стартует новая транзакция. Методы CommitTrans и RollbackTrans подтверждают или откатывают транзакцию. Разрешается произвольная глубина вложенности транзакций, то есть после старта одной транзакции может немедленно стартовать следующая и т. д. Уровни разграничения транзакций (свойство IsolationLevel) несколько отличаются от аналогичных уровней BDE и в некоторых случаях могут не поддерживаться сервером БД. Транзакция, стартующая с помощью компонента TADOConection, разделяется всеми другими связанными с ним компонентами. С помощью свойства InTransaction программа может определить, завершилась ли ранее начатая транзакция.
Begin
ADOConnection1.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;'
+ 'Data Source=C:\DATA\dbdemos.mdb';
ADOConnection1.Connected := True;
ADODataSet1.Recordset := ADOConnection1.Execute('SELECT * FROM CUSTOMER')
end;
Текст исполняемой команды хранится в свойстве CommandText компонента TADOCommand. Компонент способен за один прием исполнять одну и только одну команду.
Особенностью компонента TADOCommand является специализированный текстовый редактор, с помощью которого можно сформировать команду. Этот редактор (рисунок 10.14) вызывается щелчком на кнопке с многоточием в строке свойства CommandText инспектора объектов.
Рисунок 7.16 – Редактор команды компонента TADOCommand
Все окно редактора поделено на три части. В левой верхней части окна отображается список таблиц БД, с которой связан компонент, а в нижней левой части — список полей, выделенной таблицы. Для выделенной таблицы, всю остальную часть занимает собственно текстовый Редактор. Справочные окна в левой части лишь облегчают набор текста, который в основном формируется вручную в правом поле. Например, необходимо вручную ввести слово SELECT, выделить в нижнем списке строку * и щелкнуть на кнопке Add Field to SQL. Затем вновь вручную вводится слово FROM, в верхнем списке выделяется таблица BOOKS, выполняется щелчок на кнопке Add Table to SQL и т. д.
Как уже упоминалось, компонент TADOCommand способен возвращать записи. Для этого в него включены целых три реализации метода Execute, две из которых как раз и предназначены для создания наборов записей. Использование возвращаемого НД возможно с помощью компонента-посредника TADODataSet по следующей схеме:
ADODataSet1.Recordset := ADOCommand1.Execute;
Для создания НД множество ExecuteOptions не должно содержать значения eoExecuteNoRecords.
СВОЙСТВА, МЕТОДЫ И СОБЫТИЯ ADO КОМПОНЕНТОВ-НАБОРОВ
Методы класса TCustomADODataSet
Своеобразной особенностью ADO-наборов являются инкапсулированные в них методы SaveToFile и LoadFromFile. В ADO эти методы используются в качестве одного из возможных механизмов обмена данными между разными компьютерами, а также для отложенной обработки данных. Перед вызовами этих методов ADО-набор должен быть закрыт. После успешного вызова LoadFromFile набор автоматически открывается в том состоянии, в котором он был сохранен методом SaveToFile. ADO-наборы можно сортировать по закладкам (метод FilterOnBookmarks). Например:
procedureTForm1.Button1Click(Sender: TObject);
Var
BM1, BM2: TBookmarkStr;
Begin
withADODataSet1 do begin
BM1 := Bookmark;
MoveBy(3);
BM2 := Bookmark;
FilterOnBookmarks([BMl, BM2]);
end;
end;
Для работы в многопользовательском режиме может оказаться полезным метод Clone, с помощью которого уже созданный НД дублируется в вызывающий. Например:
ADOTable1.Open; // Создан исходный НД
ADOTable2.Clone(ADOTablel, ltReADOnly); // Создан дубликат в НД
// ADOTable2
Для ADO-наборов определен метод Requery, с помощью которого программист может обновить НД. Его действие фактически эквивалентно последовательному использованию методов Close и Open. Особенностью является то обстоятельство, что влияющие на НД свойства, такие как CursorLocation, CursotType, LockTable и т. п., остаются неизменными, в то время как в промежутке между использованием методов Close и Open эти свойства можно изменить и тем самым повлиять на результирующий НД.
Весьма необычным является метод Seek, осуществляющий поиск записи по заданному значению (значениям) ключевого поля (полей). В принципе он реализует те же действия, что и метод Locate, но отличается от него несколькими важными особенностями. Во-первых, для Locate не имеет значения, индексировано ли Поле (поля), по которому (которым) ищутся записи. В то же время Seek ищет только по индексированным полям, которые к тому же должны быть указаны в свойстве IndexNames или IndexFields. Далее, для Locate курсор не перемещается, если поиск неудачен, для Seek — перемещается всегда в зависимости от указанного параметра SeekOption (если запись не найдена, курсор перемещается: в начало НД, в конец НД, непосредственно перед искомой записью или сразу за ней). И, наконец, Seek не может вести поиск с игнорированием возможной разницы в регистре букв или по частичному совпадению поисковых значений. К сожалению, многие провайдеры OLE DB не допускают установки значений свойства IndexNames или IndexFields и, таким образом, не поддерживают метод Seek.
С помощью метода Supports можно проверить различные характеристики набора, в частности, поддерживает ли он метод Seek:
ADOTable1.Open;
if Supports([coSeek]) then
ADOTable1.Seek(90001, soAfterEQ)
else ifSupports ([coLocate]) then
ADOTable1.Locate('Number', 90001, [] );
События класса TCustomADODataSet
Некоторые события используют следующие типы данных, определяющие статус и смысл события:
typeTEventStatus = (esOK, esErrorsOccured, esCantDeny, esCancel,
esUnwantedEvent);
Здесь:
ü esOK — нет ошибок;
ü esErrorsOccured — событие вызвало ошибки;
ü esCantDeny — ожидаемую связь нельзя разорвать;
ü esCancel — ожидаемую связь можно разорвать до ее активизации;
ü esUnwantedEvent — блокирует связанные события.
typeTEventReason = (erAddNew, erDelete, erUpdate, erUndoUpdate,
erUndoAddNew, erUndoDelete, erRequery,
erResynch, erClose, erMove, erFirstChange,
erMoveFirst, erMoveNext, erMovePrevious,
erMoveLast);
Здесь:
ü erAddNew —добавлена запись;
ü erDelete — удалена запись;
ü erUpdate — запись изменена;
ü erUndoUpdate — произошел откат изменений записи;
ü erUndoAddNew — произошел откат вставки записи;
ü erUndoDelete — произошел откат удаления записи;
ü erRequery — к НД был применен метод Requere;
ü erResynch — к НД был применен метод Resync;
ü erClose — НД был закрыт;
ü erMove — курсор сместился к другой записи;
ü erFirstChange — произошло первое изменение НД;
ü erMoveFirst — курсор сместился к первой записи;
ü erMoveNext — курсор сместился к следующей записи;
ü erMovePrevious — курсор сместился к предыдущей записи;
ü erMoveLast — курсор сместился к последней записи.
Особенностью события OnEndOfRecordset является то, что оно предшествует событиям BeforeScroll и AfterScroll. В обработчике события нельзя проверять конец НД с помощью функции EOF, так как сам НД может быть частично не наполнен, если наполнение его записями идет в асинхронном режиме.
Обработчик события OnFetchProgressEvent обычно используется при длительном обращении к БД в асинхронном режиме для индикации процесса. Например:
proedureTForm1.ADODataSet1FetchProgress(DataSet: TCustomADODataSet; Progress, MaxProgress: integer;
varEventStatus: TEventStatus);
Begin
Caption := 'Процент выполнения: ' +
IntToStr(Trunc(Progress / MaxProgress * 100)) + '%' ;
Application.ProcessMessages;
end;
КОМПОНЕНТ TADOQuery
В отличие от компонента TADOCommand компонент TADOQuery преимущественно предназначен для получения набора записей из одной или нескольких таблиц БД. На самом деле компонент TADOQuery фактически целиком повторяет функциональность компонента TQuery, так как в него включен специфический метод ExecSQL, с помощью которого компонент может выполнять предложения DDL языка SQL. Сам запрос формируется в свойстве SQL.
Единственным отличием компонента TADOQuery от его BDE-аналога является свойство, с помощью которого программист может узнать или указать максимальное количество обновлений, которое сделано (или разрешается сделать) при выполнении запроса:
propertyRowsAffected: integer;
Так же как компонент TQuery, компонент TADOQuery имеет свойство DataSource, позволяющее передать параметры запроса от одного компонента другому.
КОМПОНЕНТЫ ВИЗУАЛИЗАЦИИ ДАННЫХ В Delphi
Характерной особенностью визуализации данных (вкладка Data Controls) является их подключение к необходимым компонентам-наборам TTable и TQuery через связующие компоненты - источник данных TDataSource.
В этом разделе описываются основные приемы работы с компонентом-источником TDataSource и компонентами, предназначенными для визуализации данных:
ü в виде таблицы (сетки);
ü в виде формы.
Визуализация данных в виде таблицы (сетки) осуществляется с помощью компонента TDBGrid.
Визуализация данных в виде формы представляет собой обычную форму, на которую помещены компоненты визуализации отдельных полей текущей записи. Набор этих компонент достаточно обширен – TDBText, TDBEdit и т.д.
КОМПОНЕНТ TDBGrid
Компонент TDBGrid (сетка) отображает содержимое НД в виде таблицы, в которой столбцы соответствуют полям НД, а строки - записям.
Компонент TDBText
С помощью компонента TDBText можно отображать текстовое представление различных полей НД в том виде, в котором эти поля отображаются в сетке TDBGrid. Фактически компонент повторяет функциональность метки TLabel за тем исключением, что его текст формируется автоматически на основании значения некоторого поля текущей записи.
Отображаемый компонентом текст нельзя изменять и, следовательно, с его помощью нельзя редактировать связанное с ним поле. Разумеется, тип отображаемого поля должен быть приводимым ктекстовому значению.
Для использования компонента TDBText нужно связать его с соответствующим полем НД с помощью свойств DataSource и DataField.
Компонент TDBEdit
Компонент TDBEdit позволяет редактировать значение поля текущей записи НД. Он повторяет функциональность компонента TEdit, позволяющего корректироватьтекстовое значение переменной, но источником данных и их приемником для него служит поле НД. Тип этого поля должен быть приводимым к текстовому значению. В форме, показанной на рисунке 12.9, компонент TDBEdit использован для ввода и редактирования полей дат, сумм и коэффициента скидки/наценки.
При вводе значения в компонент TDBEdit программа автоматически следит за тем, чтобы оно было совместимо по формату с полем НД. Ввод неверных значений блокируется. Например, если в компонент, связанный с полем типа дата-время, попытаться поместить произвольный текст, будет возбуждена исключительная ситуация.
Свойства, методы и события компонента аналогичны свойствам, методам и событиям стандартного компонента TEdit.
Компонент TDBCheckBox
Компонент TDBCheckBox обладает функциональностью стандартного флажка TCheckBox, но источником данных и их приемником для него служит поле НД, которое может быть логическим или символьным. В последнем случае необходимо соответствующим образом установить значения текстовых свойств ValueChecked и ValueUnchecked компонента. Например:
DBCheckBoxl.ValueChecked := 'True; Yеs; On; Да; Д';
DBCheckBoxl.ValueUnchecked := 'False; No; Off; Нет; Н';
Компонент TDBRichEdit
Компонент TDBRichEdit позволяет просматривать и корректировать информацию в мемо-поле форматированного комментария. Текст форматированного комментария может содержать фрагменты, набранные различным шрифтом, размером, стилем, цветом и т. д. В отличие от компонента TDBMemo, который позволяет работать только с однородным (неформатированным) текстом, компонент TDBRichEdit умеет интерпретировать специальные символы разметки текста в формате RTF (Rich Text Format - расширенный текстовый формат). Многие свойства, методы и события компонента аналогичны по назначению одноименным свойствам, методам и событиям компонента TRichEdit и в этом разделе не описываются.
Специфичными для компонента являются свойства DataSource, DataField, AutoDisplay и Field, описанные в предыдущем подразделе.
РЕКОМЕНДОВАННАЯ ЛИТЕРАТУРА
1. Проектирование баз данных в Delphi. Создание отчетов и распространение приложений. Методические указания к практическим занятиям и курсовому проектированию по дисциплине " к изучению и курсовому проектированию по дисциплине "Организация баз данных" для студентов направления "Компьютерная инженерия”. / Составители В.И. Павловский, В.В. Соломаха, Павловская Д.В., Павловский И. В. – Чернигов, ЧДТУ 2005.-90 с.
2. Фаронов В.В. Программирование баз данных в Delphi. Учебный курс. – СПб.: Питер, 2004.–459 с.
3. Фаронов В.В. Delphi 6. Учебный курс.-М.: Издатель Молгачева С.В., 2001.-672 с.
4. Архангельский А.Я. Программирование в Delphi 7. М.: "Бином-Пресс", 2003 г.-1152 с.
5. Грабер М. Введение в SQL. М.: "ЛОРИ", 1996 г. – 380 с.