- •Технології проектування баз даних в delphi
- •6.051001 - Метрологія та інформаційно-вимірювальні технології
- •Технології проектування баз даних в delphi
- •6.051001 - Метрологія та інформаційно-вимірювальні технології
- •1Введение
- •2Введение в базы данных
- •2.1Типы субд
- •2.2Стандарт odbc
- •2.3Технологии взаимодействия delphi с бд
- •2.3.1Особенности технологии bde
- •2.3.2Особенности технологии ado
- •2.4Таблицы бд и связи между ними
- •2.5Первичные ключи и индексы
- •2.6Демонстрационная бд "поставщик книг"
- •3Использование odbc для подключения источника данных. Псевдонимы бд
- •3.1Внешний и внутренний псевдонимы бд
- •3.1.1Создание внешнего псевдонима
- •3.1.2Проверка работоспособности внешнего псевдонима в среде Delphi
- •3.2Внутренний псевдоним бд
- •3.2.1Назначение внутреннего псевдонима бд
- •3.2.2Создание внутреннего псевдонима
- •3.2.3Преимущества использования внутреннего псевдонима и проблемы перехода на другие субд
- •4Создание проекта с бд в технологии bde
- •4.1Особенности использования bde для соединения с источником данных
- •4.2Структура проекта с бд и визуальными компонентами
- •4.3Активизация проекта
- •4.4.4Компоненты tdbGrid
- •4.5Модуль данных
- •4.5.1Создание модуля данных tDataModule
- •4.5.2Связь модуля главного окна с модулем данных
- •4.5.3Создание компонента tDatabase
- •4.5.4Создание компонента tTable
- •4.5.5Создание компонента tDataSource
- •4.5.6Связь модуля главного окна с модулем данных
- •4.5.7Связь сетки tdbGrid и навигатора dbNavigator c источником данных tDataSource
- •4.5.8Связь главный-детальный между наборами данных
- •4.5.9Задание реляционной связи между наборами данных
- •4.5.10Активизация наборов данных
- •4.5.11Недостатки полученных решений и пути их устранения
- •4.6Объекты-столбцы сетки dbGrid
- •4.6.1Создание объектов-столбцов
- •4.6.2Редактирование объекта-столбца
- •4.7Объекты-поля наборов данных
- •4.7.1Назначение объектов-полей
- •4.7.2Создание объектов-полей
- •4.7.3Присоединение к наборам данных новых полей
- •4.7.4Присоединение полей из других таблиц. Подстановочные поля
- •4.7.5Вычисляемые поля
- •4.8Обработчики событий компонент работы с бд
- •4.8.1Обработчики событий OnGetText полей нд и компонента визуализации данных tdbGrid
- •4.8.2Установка системных переменных в обработчике событя OnCreate
- •4.9Бизнес-правила и обработчики событий компонент работы с бд
- •5Sql запросы к бд
- •5.1Компонент tQuery
- •5.2Создание компонента tQuery
- •5.3Использования компонента tQuery
- •5.3.1Свойство sql компонента tQuery
- •5.3.2Методы Open и ExecSql
- •5.3.3Схема программного формирования sql-запроса
- •5.3.4Параметрические запросы
- •5.3.5Параметрические запросы и свойство DataSource компонента tQuery
- •5.3.6Связь главный-детальный с компонентом tQuery в качестве детального набора данных
- •5.4Доступ к полям запроса
- •5.4.1Обращение к значению поля при помощи свойств объектов-полей Value и AsXxxx
- •5.4.2Обращение к значению поля при помощи свойств набора данных Fields и FieldValues
- •5.4.3Обращение к значению поля при помощи функции набора данных FieldByName
- •5.5Программный доступ к данным запроса
- •5.5.1Общая схема программного доступа к данным запроса
- •5.5.2Последовательная навигация по записям
- •5.6Обзор событий компонента tQuery
- •6Хранимые процедуры и триггеры
- •6.1Хранимые процедуры
- •6.2Создание хранимых процедур
- •6.3Вызов хранимых процедур
- •6.4Триггеры
- •7Наборы данных
- •7.1Обзор событий класса tdbDataSet
- •7.1.1Реализация каскадных изменений и бизнес-правил
- •7.1.2Другие события
- •8Технология ado
- •8.1Основные особенности технологии ado
- •8.2Реализация технологии ado в Delphi
- •8.3Создание проекта с бд в технологии ado. Установка связи с бд
- •8.3.1Создание модуля данных
- •8.3.2Начало настройки связи
- •8.3.3Выбор провайдера
- •8.3.4Настройка провайдера
- •8.3.5Настройка провайдера Microsoft Jet 4.0 ole db Provider
- •8.3.6Настройка провайдера Microsoft ole db Provider for odbc Drivers
- •8.3.7Завершение настройки связи
- •8.3.8Настройка оставшихся компонент модуля данных
- •8.4Особенности использования компонентов ado
- •8.4.1Базовые объекты ado
- •8.4.2Объект Recordset
- •8.4.3Объект Command
- •8.4.8Связной компонент tadoConnection
- •8.4.9Компонент tadoCommand
- •8.5.2Специфические свойства
- •8.5Свойства, методы и события ado компонентов-наборов
- •8.5.1Общие свойства с bde-компонентами
- •8.5.3Методы класса tCustomAdoDataSet
- •8.5.4События класса tCustomAdoDataSet
- •8.6Компонент tadoDataSet
- •8.7Компонент tadoTable
- •8.8Компонент tadoQuery
- •9Компоненты визуализации данных в Delphi
- •9.1Компонент tdbGrid
- •9.1.1Свойства
- •9.1.2Дополнительные возможности сетки
- •9.2Компоненты визуализации полей текущей записи
- •9.2.1Компонент tdbText
- •9.2.2Компонент tdbEdit
- •9.2.3Компонент tdbCheckBox
- •9.2.4Компонент tdbRadioGroup
- •9.2.5Списочные компоненты
- •9.2.6Компонент tdbMemo
- •9.2.7Компонент tdbRichEdit
- •9.2.8Компонент tdbCtrlGrid
- •9.2.9Компонент tdbNavigator
- •Приложение 2. Бд "поставщик книг"
- •Рекомендованная литература
4.8.1Обработчики событий OnGetText полей нд и компонента визуализации данных tdbGrid
Событие OnGetText возникает всякий раз, когда программа обращается к полю НД с целью отображения его содержимого в любом визуализирующем компоненте, например TDBGrid. Программист в обработчике этого события должен поместить нужную строку в переменную Text соответсвующего объекта-поля.
Как видно из заголовка нашего примера в нижней сетки DBGrid2 ее 1-ый столбец должен содержать текст, составленный из значений 3-х уже существующих подстановочных объектов-полей tbMoveName, tbMoveAuthor и tbMovePublish набора данных tbMove. Напомним, что по умолчанию Delphi присваивает объекту-полю имя, полученное сцеплением имени НД - tbMove и имени поля - Name.
Чтобы реализовать такое составное поле, воспользуемся обработчиком события OnGetText объекта-поля tbMoveName набора данных tbMove.
В рассматриваемом случае строка Text объекта-поля tbMoveName получается объединением значений в полях tbMoveName, tbMoveAuthor и tbMovePublish.
Перейдите к форме модуля данных и вызовите редактор полей для НД tbMove. Щелкните на поле Name и откройте вкладку Events в окне инспектора объектов. Дважды щелкнув в правой части строки события OnGetText, напишите такой обработчик события:
procedure TDM.tbMoveNameGetText(Sender: TField;
var Text: string;
DisplayText: boolean);
begin
Text := tbMoveName.Value + '/' + tbMoveAuthor.Value + '/' +
tbMovePublish.Value;
end;
4.8.2Установка системных переменных в обработчике событя OnCreate
Во время работы программы можно заметить, что денежные суммы в сетках DBGrid1 и DBGrid2 содержат округленные до гривен значения. Такое отображение денежных сумм, предлагается по умолчанию, что не всегда допустимо.
С другой стороны программе доступны общесистемные переменные, зависящие от локализации Windows, и в том числе - переменная CurrencyDecimals, с помощью которой можно управлять форматом отображения данных типа currency.
Чтобы в денежных полях отображались не только гривны, но и копейки, создайте такой обработчик события OnCreate главной формы программы:
procedure TFinNakls.FormCreate (Sender: TObject);
begin
//Задается показ типа данных currency с двумя знаками после запятой
CurrencyDecimals := 2
end;
4.9Бизнес-правила и обработчики событий компонент работы с бд
Программа для отображения содержания накладных и связанных с ними списков книг готова. Ее можно запустить и просматривать накладные. Однако не рекомендуется вставлять, редактировать или удалять записи в накладных и списках книг, пока в программе не реализован комплекс бизнес-правил.
Бизнес-правила определяют реакцию системы на добавление, изменение или удаление данных, обеспечивая непротиворечивость и ссылочную целостность БД.
Если, например, для какой-либо накладной удалить запись о книге из ее списка книг, то программа должна автоматически изменить сумму в соответствующей накладной, количество книг на складе и сальдо партнера, в противном случае будут получены недостоверная накладная, неверное количество книг и ошибочное сальдо. Таким образом, корректная реакция программы на удаление записи о книге и есть бизнес-правило удаления книг.
Бизнес-правила разрабатываются на основе тщательного изучения автоматизируемой области человеческой деятельности.
Для файл-серверных систем они обычно реализуются в комплексе обработчиков событий AfterXXXX - BeforeXXXX компонентов-наборов данных TTable или TQuery.
В клиент-серверных и некоторых локальных системах эти действия, как правило, реализуются на сервере БД с помощью триггеров - процедур, которые автоматически запускаются при вставке, изменении или удалении записей.
Рассмотрим небольшой пример, реализующий часть бизнес-правил, связанных с удалением данных о накладной. Перед удалением данных о накладной надо удалить список связанных с ней книг, иначе в таблице MOVEBOOK появятся записи, которые ссылаются на несуществующую запись в таблице NAKLS.
Примечание. Для данного примера при правильном проектировании БД, в частности задания свойства каскадное удаление, собственно корректное удаление будет выполнено автоматически за счет средств самой СУБД. Однако при более сложных бизнес-правилах, когда удаление данных требует дополнительной обработки БД, ответственность за правильное выполнение удаления все равно ляжет на программиста.
Наиболее подходящим местом для реализации этого бизнес-правила является обработчик события BeforeDelete набора данных tbNakls. Это событие автоматически генерируется перед удалением записи.
Перейдите к форме модуля данных, щелкните на НД tbNakls в правой панели модуля и дважды щелкните в строке события BeforeDelete в окне инспектора объектов. Напишите такой обработчик события:
procedure TDM.tbNaklsBeforeDelete(DataSet: TDataSet);
begin
while not tbMove.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) while not 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; |
