close

Вход

Забыли?

вход по аккаунту

?

666.Использование среды C++ Builder для работы с базами данных

код для вставкиСкачать
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ
УЧРЕЖДЕНИЕ
ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
«ВОРОНЕЖСКИЙ ГОСУДАРСТВЕННЫЙ
УНИВЕРСИТЕТ»
ИСПОЛЬЗОВАНИЕ СРЕДЫ C++ BUILDER
ДЛЯ РАБОТЫ С БАЗАМИ ДАННЫХ
Учебно-методическое пособие для вузов
Составитель
Ю.А. Крыжановская
Издательско-полиграфический центр
Воронежского государственного университета
2009
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Утверждено
научно-методическим
24 ноября 2008 г., протокол № 3
советом
факультета
ПММ
Рецензент канд. физ.-мат. наук, доц. каф. МО ЭВМ О.Д. Горбенко
Учебно-методическое пособие подготовлено на кафедре технической кибернетики и автоматического регулирования факультета прикладной математики, информатики и механики Воронежского государственного университета.
Рекомендуется для студентов 5 курса д/о и магистров 1 года обучения факультета прикладной математики, информатики и механики.
Для специальности 010501 – Прикладная математика и информатика
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Содержание
Введение............................................................................................................ ..4
Основные компоненты для работы с базами данных ................................... ..5
Модули данных ................................................................................................ 12
Динамическое создание базы данных ............................................................ 12
Добавление полей в таблицу ........................................................................ 15
Создание базы данных из приложения........................................................ 16
Обработка событий базы данных................................................................. 17
Проверка данных ........................................................................................... 20
SQL-ориентированный доступ........................................................................ 22
Создание статического запроса.................................................................... 22
Генератор запросов ....................................................................................... 23
Динамические запросы ................................................................................. 25
Хранимые процедуры ...................................................................................... 27
Утилиты............................................................................................................. 27
Задания .............................................................................................................. 28
Список литературы .......................................................................................... 29
3
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
ВВЕДЕНИЕ
Borland C++ Builder представляет собой средство быстрой разработки приложений, позволяющее создавать приложения на языке C++, используя компоненты.
Компоненты — это своеобразные «строительные блоки» для приложений. Специализированные объекты-компоненты со своими возможностями можно использовать и объединять так, как нужно для достижения
поставленных целей. Компоненты, например, являются основой широко
используемой ActiveX-технологии.
В C++ Builder хорошо организована работа с компонентами. C++
Builder работает просто и последовательно во многом благодаря тому, что
сам построен на компонентах. Компоненты весьма близки к «чистому»
программированию на C++, а также существенно облегчают процесс разработки.
Есть еще один важный аспект C++ Builder (в дальнейшем будем коротко записывать как CBuilder). В этой системе зашита мощная и гибкая
среда программирования баз данных (БД). Используя CBuilder, можно создать приложения, работающие как с однопользовательскими базами данных (БД), так и с серверными СУБД, такими как Oracle, Sybase, Informix,
Interbase, MS SQL Server, DB2, а также с ODBC-источниками (Open
Database Connectivity, базы данных с открытой связью). Интерфейс с базами данных во многих системах C++ состоит из набора объектов, которые
являются тонкими обложками, скрывающими под собой низкоуровневые
функции баз данных. Зачастую объекты баз данных содержат в себе методы, требующие большого количества параметров для открытия и инициализации присоединения к базе данных ODBC. В случае использования
CBuilder разработчику доступен целый набор drag-and-drop компонентов
баз данных, встроенный в систему. Присутствуют управляющие элементы
для работы с данными (data-aware controls), которые вообще не требуют
программирования. Можно написать вполне законченный редактор баз
данных, который бы добавлял новые, редактировал существующие и удалял ненужные записи, не написав ни одной строчки кода на C++.
Можно сказать, что CBuilder предоставляет широкие возможности
по использованию компонентной технологии, работе с базами данных,
таблицами, запросами SQL, а также поддерживает такие технологии, как
шаблоны (templates), именованные области видимости (namespaces), обработка исключительных ситуаций (exception handling) и библиотека стандартных шаблонов (Standard Template Library, STL).
Данное учебно-методическое пособие содержит базовые сведения об
использовании среды разработки CBuilder для решения простых задач по
работе с базами данных. За рамками оставлено рассмотрение, например,
использования хранимых процедур, механизма транзакций. Пособие со4
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
держит иллюстрирующие примеры, которые сопровождаются заданиями
для самостоятельного выполнения. В завершение приводятся задания, позволяющие проверить усвоение материала. Материал пособия апробирован
при проведении лабораторных работ по спецкурсу «Основы программирования на C++». Пособие предназначено студентам 5 курса дневного отделения, изучающим спецкурс «Основы программирования на С++», а также
магистрам 1 года обучения, изучающим спецкурс «Программирование на
С++ (доп. главы)». При подготовке материалов были использованы литературные и интернет-источники [1–6]. Абсолютно необходимым инструментом при работе с любой средой разработки является встроенная справочная система, а при решении сложных задач часто приходится изучать и
исходные тексты библиотеки визуальных компонентов.
Работа с пособием предполагает знание основ баз данных и СУБД в
рамках курса «Базы данных и экспертные системы», читаемого на 4 курсе
дневного отделения факультета ПММ, а также умение пользоваться стандартными визуальными компонентами.
ОСНОВНЫЕ КОМПОНЕНТЫ ДЛЯ РАБОТЫ С БАЗАМИ ДАННЫХ
Для выполнения базовых операций с базами данных используются
вкладки Data Access (компоненты для доступа к информации) и Data Controls, компоненты которой служат для обеспечения отображения и редактирования записей на форме приложения и имеют связь с полями таблиц
БД, палитры компонентов. Эти компоненты аналогичны тем, что знакомы
по среде Delphi. Коротко рассмотрим основные из них. Подробное описание компонентов можно увидеть в [4–6].
Набор данных в CBuilder – объект, состоящий из набора записей, каждая из которых состоит из полей и указателя текущей записи. Набор данных
может иметь полное соответствие с реально существующей таблицей или
быть результатом запроса, он может быть частью таблицы или объединять
между собой несколько таблиц. Набор данных в CBuilder является потомком
абстрактного класса TDataSet. Классы TQuery, TTable и TStoredProc – наследники TDBDataSet, который является наследником TDataSet. TDataSet содержит абстракции, необходимые для непосредственного управления таблицами или запросами, обеспечивая средства для того, чтобы открыть таблицу
или выполнить запрос и перемещаться по строкам.
Компонент DataSource действует как посредник между компонентами TTable, TQuery, TStoredProc и элементами управления, обеспечивающими представление данных на форме, и управляет связями с данными
в компонентах со страницы Data Controls (например, DBGrid, DBEdit и
др.). Компонент DataSource, как правило, связан с одним компоненом
TTable или TQuery и с одним или более компонентами для отображения
данных.
5
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Компонент TTable предоставляет доступ к одной таблице. Cобытия
этого компонента позволяют строить и контролировать поведение приложений. Для использования компонента TTable следует:
– разместить TTable на форме или в модуле данных (см. ниже);
– задать значение свойств DatabaseName и TableName;
– разместить на форме или в модуле данных компонент DataSource и
установить значение свойства DataSet равным имени компонента TTable;
– компоненты со страницы Data Controls расположить на форме и
связать с компонентом DataSource для отображения данных.
Так как базы данных предназначены не только для хранения, но и
для выбора и обработки информации, одним из важнейших аспектов их
использования является создание запросов к ним. Для создания запроса
используется компонент TQuery. Он позволяет использовать операторы
SQL для определения или создания наборов данных, которые можно отображать, вставлять, удалять и редактировать. Отметим, что язык запросов
SQL (Structured Query Language), обычно применяемый при работе с серверными СУБД, может быть использован и при работе с таблицами формата dBase и Paradox. Пример использования компонента TQuery будет рассмотрен далее.
Объекты класса TField являются свойством объекта TDataSet. Свойство Fields объекта типа TDataSet позволяет обращаться к отдельным полям набора данных и является массивом объектов TField, динамически
создающимся во время выполнения приложения. Элементы массива соответствуют колонкам таблицы. Объект TField не делает никаких предположений относительно типов данных, с которыми он связан, и имеет несколько свойств, позволяющих установить или вернуть обратно значения
поля, например AsString, AsBoolean, AsFloat, AsInteger. Fields Editor позволяет создать статический список полей таблицы, добавляемых к описанию
класса формы на этапе проектирования приложения. При внесении колонок с использованием Fields Editor для каждого из полей, добавленных к
TDataSet, возникают объекты TField, после чего можно увидеть эти поля в
инспекторе объектов и использовать в приложениях их свойства, события
и методы, а ссылки на них появятся в h-файле формы. Fields Editor используется следующим образом:
– разместить TTable или TQuery на форме, указать DatabaseName и
имя таблицы или свойство SQL для TQuery;
– для компонента TDataSet вызвать контекстное меню, в котором
выбрать Fields Еditor;
– снова вызвать контекстное меню и выбрать опцию Add Fields
(имена всех колонок таблицы или запроса появятся в диалоговой панели
Add Fields), выбрать поля для внесения в список объектов, нажать OK;
– для создания вычисляемого поля на основе имеющихся полей из
контекстного меню выбрать New Field для создания нового поля на основе
6
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
существующего или для создания вычисляемого поля (в дальнейшем следует создать код обработчика события OnCalcFields компонента TTable,
где и производятся необходимые вычисления);
– для удаления статического поля из списка нужно в контекстном
меню выбрать Delete.
Если применить операцию drag-and-drop к выделенным в Fields
Editor полям, перенеся их на форму, можно получить готовую форму с необходимым набором интерфейсных элементов.
Компоненты DBLookup используются при наличии связанных таблиц, когда необходимо вывести на экран описательную информацию вместо поля, содержащего ее код. Таких компонентов четыре. DBLookupList
и DBLookupListBox позволяют вывести на экран набор вариантов, основанных на значении в другой таблице. Эти компоненты отличаются от
компонента DBListBox тем, что позволяют согласовать выбранное значение из списка с текущей строкой другой таблицы БД, тогда как для
DBListBox список значений для выбора определен заранее и не имеет отношения к таблицам БД. Похожи на них и компоненты DBLookupCombo
и DBLookupComboBox, за исключением возможности пользователя выбирать значение в списке либо вводить новое.
Компоненты
DBLookupCombo и DBLookupComboBox аналогичны компоненту
ComboBox, но позволяют согласовать выбранное значение с текущей строкой другой таблицы БД.
При рассмотрении различных примеров работы с БД будем пользоваться таблицами базы данных BCDEMOS, содержащейся в комплекте поставки CBuilder.
Лабораторная работа № 1
Рассмотрим простой пример для просмотра полей БД [3]. Создадим
форму, показанную на рис. 1, добавив на пустую форму объекты
TStringGrid, TMainMenu, TOpenDialog и TTable. В данном случае напрямую устанавливать свойства объектов grid, dialog или table не будем. Объект main menu должен содержать пункт «Файл» с подпунктами «Открыть»
и «Выход». Пункт меню «Открыть» будет использоваться для выбора таблицы базы данных для просмотра, а пункт «Выход» — для закрытия приложения.
7
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Рис. 1. Форма программы просмотра полей базы данных
Создадим таблицы типов полей. Типы полей хранятся в БД как числовые значения типа TFldType. Для отображения этих данных в более
удобном виде следует в начало исходного файла Unit1.h добавить код:
typedef struct
{
int nCode;
char *strDesc;
} DbFieldType;
DbFieldType sFieldTypes[] =
{
{ftUnknown, "Неизвестно или не определено"},
{ftString, "Символьное или строковое поле"},
{ftSmallint, "16-битное целое поле"},
{ftInteger, "32-битное целое поле"},
{ftWord, "16-битное беззнаковое целое поле"},
{ftBoolean, "Логическое поле"},
{ftFloat, "Поле чисел с плавающей точкой"},
{ftCurrency, "Денежное поле"},
{ftBCD, "Двоично-кодированное десятичное поле"},
{ftDate, "Поле даты"},
{ftTime, "Поле времени"},
{ftDateTime, "Поле даты и времени"},
{ftBytes, "Фиксированное количество байт (двоичное
представление)"},
{ftVarBytes, "Переменное количество байт (двоичное
представление"},
{ftAutoInc, "Автоматически увеличивающееся 32-битное целое поле
счетчика"},
{ftBlob, "Поле Binary Large Object (большой двоичный объект)"},
{ftMemo, "Поле memo (строка неограниченной длины)"},
{ftGraphic, "Поле растрового рисунка"},
{ftFmtMemo, "Поле форматированного memo"},
{ftParadoxOle, "Поле Paradox OLE"},
{ftDBaseOle, "Поле dBase OLE"},
{ftTypedBinary, "Типизированное двоичное поле"},
{-1,""}
};
Эта таблица будет ставить в соответствие типы данных (символы
ftxxx) и строки, которые характеризуют тип поля.
8
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Для преобразования типа поля в его описание придется добавить
вспомогательную функцию GetFieldTypeDescription, получающую один
аргумент — тип поля и возвращающую строку, описывающую это поле. В
метод GetFieldTypeDescription необходимо добавить код:
char *TForm1::GetFieldTypeDescription(int nInd)
{
for (int i=0; sFieldTypes[i].nCode != -1; ++i)
if (sFieldTypes[i].nCode == nInd)
return sFieldTypes[i].strDesc;
return "";
}
Типам полей поставлены в соответствие строки, которые и будут использоваться для вывода на экран, следующим этапом будет написание
обработчика открытия базы данных и загрузки в сетку информации из базы. Для команды меню «Файл» «Открыть» напишем обработчик открытия
БД. В метод Open1Click добавим:
void __fastcall TForm1::Open1Click(TObject *Sender)
{
OpenDialog1->Filter = "Файлы баз данных dBase|*.dbf";
if (OpenDialog1->Execute())
{
// Пытаемся открыть выбранную базу данных
Table1->DatabaseName = ExtractFilePath(OpenDialog1->FileName);
// Определяем имя таблицы
Table1->TableName = ExtractFileName(OpenDialog1->FileName);
// Делаем таблицу активной
Table1->Active = true;
// Загружаем сетку с частями таблицы
StringGrid1->RowCount = Table1->FieldCount;
StringGrid1->ColCount = 4;
// Устанавливаем ширину столбцов
StringGrid1->ColWidth[0] = 30;
StringGrid1->ColWidth[1] = StringGrid1->ClientWidth/3 - 10;
StringGrid1->ColWidth[2] = StringGrid1->ClientWidth/3 - 10;
StringGrid1->ColWidth[3] = StringGrid1->ClientWidth/3 - 10;
// Устанавливаем заголовки
StringGrid1->Cells[0][0] = "№ поля";
StringGrid1->Cells[0][0] = "Имя поля";
StringGrid1->Cells[0][0] = "Тип поля";
StringGrid1->Cells[0][0] = "Размер";
for (int i=1; i<Table1->FieldCount; ++i)
{
StringGrid1->Cells[0][i] = AnsiString(i);
StringGrid1->Cells[1][i] = Table1->FieldDefs->Items[i]->Name;
StringGrid1->Cells[2][i] =
GetFieldTypeDescription(Table1-> FieldDefs->Items[i]->DataType);
StringGrid1->Cells[3][i] = AnsiString(Table1->FieldDefs->
Items[i]->Size);
}
}
}
9
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Объект TOpenDialog возвращает полный путь к выбранному пользователем файлу в свойстве FileName. Мы знаем, что выбран файл корректного типа, т. к. свойство Filter установлено так, чтобы допустить
только файлы dBase (DBF). Поэтому можно использовать вспомогательную функцию ExtractFilePath для получения только имени каталога и
вспомогательную функцию ExtractFileName для получения имени файла с
выбранной таблицей. После того как обе функции были использованы, мы
«открываем» базу данных, устанавливая свойство Active в true.
Задание. Приведенный код мог привести к возникновению исключительной ситуации. Обработайте эту исключительную ситуацию.
После открытия базы данных число строк в сетке устанавливается в
значение, равное хранящемуся в свойстве FieldCount числу полей. После
того как сетка инициирована, ширина и заголовки установлены, одно за
другим опрашиваются поля и данные по каждому загружаются в ячейки
клетки.
Cтоит обратить внимание на преобразование номера поля в строку
при помощи класса AnsiString. Этот класс поддерживает большинство методов класса string и используется в ситуации, когда требуется строка типа
принятой в языке Pascal. Все методы VCL, работающие со строками, допускают AnsiString в качестве типа аргумента.
Последним шагом для завершения программы будет осуществление
ее закрытия при выборе команды меню «Файл» «Закрыть». Добавим новый
обработчик для команды меню «Выход», в Exit1Click запишем:
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
Application->Terminate();
}
Простая программа просмотра баз данных успешно завершена. Теперь ее можно скомпилировать и запустить, выбрать базу данных для просмотра. Примеры можно найти в подкаталоге CBuilder\Examples\Data основного каталога CBuilder. На рис. 2. показано окно программы просмотра
с отображенным в нем файлом Clients.dbf.
Рис. 2. Программа просмотра
10
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Лабораторная работа № 2
В этом примере [4] рассмотрим использование компонентов просмотра баз данных, а также способ установления связей между таблицами.
Будем использовать таблицы CUSTOMER (заказчики) и ORDERS (заказы)
из базы данных BCDEMOS и компонент DBLookupListBox для отображения имени компании, соответствующего значению CustID, находящемуся в
таблице ORDERS.
Откроем новый проект и сохраним главную форму как DBLOOK1.CPP.
Разместим на форме компоненты TTable, DataSource, DBGrid и DBNavigator,
пропишем в свойстве Database Name Table1 значение BСDEMOS, в свойстве
TableName – значение ORDERS.DB, а свойству Active присвоим значение
true. Для компонента DataSource1: свойству DataSet присвоим значение
Table1, свойству AutoEdit – значение false. Свойству DataSource компонентов
DBGrid1 и DBNavigator1 присвоим значение DataSource1. Далее используем
Fields Editor для внесения в набор данных Table1 поля OrderNo, CustNo,
SaleDate, ItemsTotal, AmountPaid. Расположим поля в Fields Editor так, чтобы
OrderNo был первым, а CustNo – вторым.
Добавим компонент DBLookupListBox и установим его свойство
DataSource равным DataSource1, а свойство DataField равным CustNo. Поместим на форму новые компоненты TTable и DataSource. Установим
свойство DatabaseName для компонента Table2 равным BCDEMOS, свойство TableName равным CUSTOMER.DB, а свойство Active равным true.
Свяжем DataSource2 с Table2, а компонент DBLookupListBox1 с
DataSource2, установив значение свойства ListSource компонента
DBLookupListBox1 равным DataSource2, свойства KeytField равным
CustNo, а свойства ListField равным Company.
В компоненте DBLookupListBox будет выделено название компании,
соответствующее значению CustNo в текущей строке DBGrid (рис. 3).
Рис. 3. Использование компонента DBLookupListBox
11
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Можно использовать DBLookupListBox для выбора заказчика по
имени, при этом в таблице Orders будет устанавливаться соответствующее
значение CustNo.
Задание. Создайте приложение с применением DBLookupComboBox.
Лабораторная работа № 3 (самостоятельная)
Для таблицы Country.db создайте вычисляемое поле Density (Плотность) с отображением полей Name, Area, Population, используя Fields Editor.
МОДУЛИ ДАННЫХ
В рассмотренном выше примере компоненты страницы Data Access
размещались на форме, но при наличии на форме большого количества невизуальных компонентов проектирование пользовательского интерфейса
сложнее. Гораздо более удобным представляется отделение компонентов
доступа к данным от интерфейсных элементов. Для этого есть специальный тип, называемый модулем данных, – TDataModule. Компонент этого
типа можно условно считать специальным видом формы, хотя он и порожден непосредственно от TСomponent. Он может содержать компоненты со
страницы Data Access, а сам не виден пользователю во время выполнения.
При использовании модуля данных ссылка на соответствующий h-файл
помещается в модуль, связанный с главной формой приложения.
Задание. Применить модуль данных в работе 2.
ДИНАМИЧЕСКОЕ СОЗДАНИЕ БАЗЫ ДАННЫХ
Рассмотрим приложение, которое позволит пользователю определять
схему базы данных [3]. Поля будут добавляться в таблицу, имя и каталог
устанавливаться, база данных создаваться — и все в нескольких десятках
строках кода. При этом большая часть этих строк относится скорее к интерфейсу с пользователем, чем к созданию базы.
Рис. 4. Форма приложения создания баз данных
12
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
На рис. 4 показана форма, которая будет использоваться для создания
баз данных. Следует обратить внимание на несколько важных моментов. Вопервых, на форме нет компонентов, воспринимающих данные (сетка относится к TStringGrid), т. к. в интерфейсе этой формы не предполагается использование управляющих элементов для БД. Все, что будет сделано, будет
сделано на низком уровне доступа к базам данных. Во-вторых, на форме нет
объекта TTable. Этот компонент будет использоваться для создания базы
данных, но в этом примере он создается динамически.
Лабораторная работа № 4
В код формы нужно добавить ту же таблицу описание/код, что в
первой работе. В том случае объект field definitions использовался для
указания пользователю на описание полей. В новом примере описание полей будет использоваться для выбора из них типа поля и последующего
установления соответствия ему типа действительного (физического) поля для непосредственного описания поля в таблице. Добавим в начало
файла Unit1.cpp следующий код:
typedef struct
{
Db::TFieldType nCode;
char *strDesc;
} DbFieldType;
DbFieldType sFieldTypes[] =
{
{ftUnknown, "Неизвестно или не определено"},
{ftString, "Символьное или строковое поле"},
{ftSmallint, "16-битное целое поле"},
{ftInteger, "32-битное целое поле"},
{ftWord, "16-битное беззнаковое целое поле"},
{ftBoolean, "Логическое поле"},
{ftFloat, "Поле чисел с плавающей точкой"},
{ftCurrency, "Денежное поле"},
{ftBCD, "Двоично-кодированное десятичное поле"},
{ftDate, "Поле даты"},
{ftTime, "Поле времени"},
{ftDateTime, "Поле даты и времени"},
{ftBytes, "Фиксированное количество байт (двоичное
представление)"},
{ftVarBytes, "Переменное количество байт (двоичное
представление"},
{ftAutoInc, "Автоматически увеличив. 32-битное целое поле
счетчика"},
{ftBlob, "Поле Binary Large Object (большой двоичный объект)"},
{ftMemo, "Поле memo (строка неограниченной длины)"},
{ftGraphic, "Поле растрового рисунка"},
{ftFmtMemo, "Поле форматированного memo"},
{ftParadoxOle, "Поле Paradox OLE"},
{ftDBaseOle, "Поле dBase OLE"},
{ftTypedBinary, "Типизированное двоичное поле"},
};
13
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Нужно также знать, сколько элементов в списке, чтобы иметь возможность добавить его в комбинированный список ниже в коде. Можно
просто использовать числовое значение, равное количеству элементов в
списке (22), но это приведет к возможности появления в будущем ошибок,
связанных с добавлением или удалением элементов из списка. Однако
препроцессор C++ Builder позволяет применить полезную хитрость. Добавим следующий код прямо после массива элементов структуры:
#define NumberOfFieldTypes (sizeof(sFieldTypes)/sizeof\
(sFieldTypes[0]))
Оператор sizeof возвращает размер (в байтах) переменной, переданной ему в качестве аргумента. В случае массива элементов структуры каждый элемент имеет свой специфический размер (обычно 8 байт). Размер
специфического элемента, тем не менее, если поделить на него произведение размеров, позволит получить общее количество элементов. Формула
будет выглядеть примерно так:
int nTotalEntries = (nNumberOfEntries * nSizeOfOneEntry) /
nSizeOfOneEntry;
Этот код сводится к тождеству nTotalEntries = nTotalEntries. Это
все, что мы используем в блоке #define, описанном выше, не заботясь о
том, чему равны nNumberOfEntries и nSizeOfOneEntry.
Следующее, что нужно, — изменить конструктор формы, вставив
туда объект TTable, который будет использоваться, а также кое-что убрать
из этого объекта, чтобы его действительно можно было использовать для
создания таблицы. В конструктор объекта Form1 добавим:
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
Table = new Table(this);
Table->Active = false;
Table->FieldDefs->Clear();
Table->IndexDefs->Clear();
}
Как видно из приведенного выше кода, в конструкторе формы создается объект TTable. Это позволит позже использовать его напрямую. Вызовы Clear для массивов описаний полей и индексов не являются здесь необходимыми, т. к. эти объекты при создании по умолчанию являются пустыми. Аналогично TTable создается со свойством Active = false. Однако
хорошей практикой будет не полагаться ни на что при работе с объектами,
а самостоятельно устанавливать все, что нужно в конструкторе.
Следующий шаг — инициализация сетки и комбинированного списка, чтобы они выглядели корректно с момента запуска программы. Для
этого добавьте новый обработчик для события формы OnCreate, а в соответствующий метод FormCreate – следующий код:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
StringGrid->ColCount = 5;
StringGrid->Cells[0][0] = "Поле";
14
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
StringGrid->Cells[1][0] = "Имя";
StringGrid->Cells[2][0] = "Тип";
StringGrid->Cells[3][0] = "Длина";
StringGrid->Cells[4][0] = "Обязательное";
StringGrid->RowCount = 1;
// Загружаем комбинированный список
for (int i=0; i<NumberOfFieldTypes; ++i)
ComboBox->Items->Add(sFieldTypes[i].strDesc);
}
}
Далее нужно предоставить пользователю возможность добавлять поля в базу данных и отображать их при помощи сетки.
Добавление полей в таблицу
Для того чтобы добавить новое поле в таблицу, пользователь вводит
имя поля и его размер в соответствующих полях ввода и выбирает тип поля из комбинированного списка, после чего нажимает кнопку «Добавить».
Но с базой данных ничего не происходит, пока пользователь не введет каталог базы данных и имя таблицы и не нажмет кнопку «Создать». Добавим
обработчик события для кнопки «Добавить». В метод формы ButtonAddClick запишем:
//————————————————————————————
void __fastcall TForm1::ButtonAddClick(TObject *Sender)
{
char szBuffer[ 80 ];
strcpy (szBuffer, Edit2->Text.c_str());
unsigned short nSize = (unsigned short)atoi(szBuffer);
// Проверяем, нужно ли задавать размер
if (sFieldTypes[ComboBox1->ItemIndex].nCode != ftString)
nSize = 0;
// Устанавливаем описания полей
Table1->FieldDefs->Add(Edit1->Text,
sFieldTypes[ComboBox1->ItemIndex],
nCode, nSize, CheckBox1->Checked);
// Переходим к следующей строке
StringGrid1->RowCount++;
// Теперь заполняем сетку данными
int nRow = StringGrid1->RowCount-1;
StringGrid1->Cells[0][nRow] = AnsiString(nRow);
StringGrid1->Cells[1][nRow] = Edit1->Text;
StringGrid1->Cells[2][nRow] =
sFieldTypes[ComboBox1->ItemIndex].strDesc;
StringGrid1->Cells[3][nRow] = Edit2->Text;
if (CheckBox1->Checked)
StringGrid1->Cells[4][nRow] = "Yes";
else
StringGrid1->Cells[4][nRow] = "No";
}
В этом коде мы сначала получаем необходимую информацию от различных элементов формы. Поле редактирования имени используется на15
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
прямую при добавлении описания поля в базе. Выбранный элемент комбинированного списка используется для нахождения действительного типа
поля в структуре, хранящей данные о соответствии типов полей их описаниям.
Есть две важные вещи, которые надо отметить при работе с полем
размера. Во-первых, не следует передавать текст для поля редактирования
прямо в функцию, даже используя метод c_str() объекта TEdit. При этом
небезопасно изменять строку прямо в поле объекта TEdit. Поэтому строка
копируется в символьный буфер, а он используется для получения размера
поля. Вторым важным аспектом, касающимся добавления размера полю,
является дилемма — разрешен размер или нет. Для всех полей, кроме полей строкового (символьного) типа, размер не только не используется, но и
не разрешается для использования. Если позволить пользователю ввести
размер для не строкового поля и передать его в метод Add объекта field
definitions, это приведет к ошибке, сгенерированной объектом, и метод не
будет выполнен. Поэтому тип поля проверяется перед добавлением размера, и для не строковых типов размер устанавливается (который, кстати, типа unsigned short, а не int) в 0.
После того как поле благополучно добавлено в структуру базы данных, информация о нем отображается в сетке и пользователь может продолжать вводить другие поля.
Можно несколько облегчить жизнь пользователю, проверив, допустимо для выбранного им типа поля задание размера или нет. Проверим это
и обработаем результат, сделав недоступным для редактирования поле
ввода размера для случая выбора типа поля без размера. Добавим в форму
новый обработчик для события OnChange комбинированного списка, а в
метод ComboBox1Change — код:
void __fastcall TForm1::ComboBox1Change(TObject *Sender)
{
if (sFieldTypes[ComboBox1->ItemIndex].nCode != ftString)
{
Edit2->Enabled = false;
}
else
Edit2->Enabled = true;
}
Создание базы данных из приложения
Когда пользователь уже добавил несколько полей и готов создать базу данных на диске в каталоге и файле, которые он выбрал для новой таблицы, значит, пришло время создать базу данных непосредственно из приложения. Добавим в метод ButtonCreateClick (Создать) следующее:
16
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
void __fastcall TForm1::ButtonCreateClick(TObject *Sender)
{
// Устанавливаем название базы данных и имя таблицы
Table1->DatabaseName = Edit3->Text;
Table1->TableName = Edit4->Text;
// Устанавливаем тип таблицы в dBase
Table1->TableZType = ttDBase;
// Создаем таблицу
Table1->CreateTable();
// Удаляем объект
delete Table1;
// Уведомляем пользователя
MessageBox1(NULL, "База данных создана!", "Подтверждение", MB_OK);
// Закрываем приложение
Application->Terminate();
}
Первый шаг в процессе создания базы данных — присвоение имени
базы данных и таблицы. Это определяет, где на самом деле будет создана
база. Можно ввести любое допустимое название каталога и файла. После
присвоения имен надо установить тип создаваемой базы данных. Система
CBuilder по умолчанию умеет создавать таблицы dBase и Paradox. С соответствующим ODBC-драйвером можно создавать также другие типы таблиц.
После того как база данных была успешно создана (следует отметить, что в коде нет проверки возможных ошибок, которую обязательно
надо будет осуществлять в реальных приложениях), объект TTable удаляется (чтобы избежать потери памяти в системе), а пользователь извещается
о создании базы. После чего приложение закрывается. Работу приложения
не обязательно прекращать в этот момент, при необходимости можно создать и инициализировать новый объект TTable и позволить пользователю
создавать много баз данных за один запуск программы.
Обработка событий базы данных
В комплекте CBuilder поставляется Мастер форм баз данных
(Database Form Wizard), позволяющий создать законченную систему, не
требующую дополнительного кодирования для добавления данных.
Задание. Проделайте любую из приведенных выше работ с использованием Мастера форм.
Кроме того, CBuilder посредством программирования событий и перехватов сообщений (hooks) предоставляет в распоряжение программиста
богатые возможности по проверке, манипулированию и изменению данных до или после их ввода в базу данных.
Ниже будут рассмотрены некоторые возможности проникновения в
код работы с базой данных, причем бóльшая часть работы по добавлению,
изменению и удалению данных из таблицы БД будет оставлена системе.
17
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Лабораторная работа № 5
Для выбора базы данных есть несколько вариантов. Можно использовать одну из существующих баз — из числа поставляемых с CBuilder
или из находящихся в системе или же создать новую базу данных. Воспользуемся программой создания баз данных из предыдущего примера.
Создадим БД «Адресная книга». Поля и типы приводятся в табл. 1.
Таблица 1
Формат полей базы данных адресов
Поле
Тип
Last Name
Символьное поле в 40 символов
First Name
Символьное поле в 40 символов
Address Line 1
Символьное поле в 40 символов
Address Line 2
Символьное поле в 40 символов
City
Символьное поле в 60 символов
State
Символьное поле в 10 символов
ZIP Code
Символьное поле в 12 символов
Phone Number
Символьное поле в 14 символов
После того как при помощи программы создания баз данных будет
создана новая таблица, воспользуемся мастером форм для создания новой
формы для нового приложения. Первое изменение, которое будет сделано в
форме, — в ее нижнюю часть будет добавлена панель состояния (status bar)
для отображения статистической информации об изменениях, сделанных
пользователем в таблице базы данных. Измените форму, сгенерированную
мастером форм БД, чтобы она выглядела так, как показано на рис. 5.
Рис. 5. Форма контроля базы данных с панелью состояния
Для того чтобы отследить изменения, сделанные пользователем в записях БД, надо узнать, когда и какие события происходят в «жизни» записи. Если пользователь нажимает кнопку «+» объекта TDBNavigator, то в
базу данных добавляется новая запись. Изменение существующей записи
18
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
происходит, если пользователь переходит к какой-либо записи, используя
одну из кнопок перемещения объекта TDBNavigator, и изменяет ее перед
тем, как перезаписать в базу. В обоих случаях событие, возникающее в базе данных, называется Post (прописывание) и появляется каждый раз, когда запись пишется в базу данных, вне зависимости от того, в первый раз
или после изменения. Поэтому будем отслеживать предшествующее действие — добавление или перемещение по базе. Для этого добавим в форму флаг состояния, а также счетчики количества добавлений, изменений и
удалений за текущий сеанс работы программы.
Изменим заголовочный файл формы, добавив в описание формы новые переменные, как показано ниже.
private; // private declarations
int FnNumAdds;
int FnNumUpdates;
int FnNumDeletes;
bool FbUpdateMode;
void UpdateStatusBar(void);
Здесь же находится функция UpdateStatusBar, которая будет использована для переноса новых данных в блоки панели состояния.
Теперь инициализируем переменные в конструкторе формы. Счетчики устанавливаются в 0, а флаг режима (FbUpdateMode) – в false. Таким
образом, полный код конструктора будет:
__fastcall TForm2::TForm2(TComponent *Owner): TForm(Owner)
{
FnNumAdds = 0;
FnNumUpdates = 0;
FnNumDeletes = 0;
FbUpdateMode = false;
}
Теперь добавим алгоритм для логической функции обновления панели
состояния. Ниже приводится код, в котором каждой секции (panel) панели
состояния присваиваются новые данные по отображаемой ей информации:
void TForm2::UpdateStatusBar(void)
{
StatusBar1->Panels->Items[0]->Text =
"Добавлено записей: " + AnsiString(FnNumAdds);
StatusBar1->Panels->Items[1]->Text =
"Удалено записей: "+ AnsiString(FnNumDeletes);
StatusBar1->Panels->Items[2]->Text =
"Изменено записей: " + AnsiString(FnNumUpdates);
}
Чтобы обработать событие Post, добавим обработчик события
AfterPost (по факту записи) объекта TTable, а в него добавим код:
void __fastcall TForm2::Table1AfterPost(TDataSet *DataSet)
{
if (FbUpdateMode)
FnNumUpdates++;
else
19
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
FnNumAdds++;
UpdateStatusBar();
}
Если пользователь добавляет новую запись в базу данных, объектом
TTable генерируется событие AfterInsert. Для каждого события After есть
соответствующее событие Before, т. е. если нужно обработать события
BeforeInsert или BeforePost, можно добавить обработчики и для них. Чтобы отследить факт добавления новой записи в базу, в обработчик события
AfterInsert добавим:
void __fastcall TForm2::Table1AfterInsert(TDataSet *DataSet)
{ FbUpdateMode = false; }
Аналогично, если пользователь изменяет существующую запись,
происходит событие AfterEdit. Это событие можно использовать для того,
чтобы дать знать форме, что мы находимся в режиме редактирования. Для
обработчика события AfterEdit код будет выглядеть так:
void __fastcall TForm2::Table1AfterEdit(TDataSet *DataSet)
{
FbUpdateMode = true; }
Последнее событие, которое требуется перехватить, — это событие,
возникающее при удалении записи из базы данных (AfterDelete):
void __fastcall TForm2::Table1AfterDelete(TDataSet *DataSet)
{
FnNumDeletes ++;
UpdateStatusBar();
}
Следует обратить внимание на то, что панель состояния при удалении обновляется. Это потому, что в базе данных больше нет изменений,
связанных с удалением, которые можно было бы отследить. В случае же
добавления или обновления, однако, никаких действий на самом деле производиться не будет до тех пор, пока пользователь не зафиксирует изменения в базе, что вызовет событие Post. Поэтому надо отследить событие
Post и соответствующим образом обновить панель состояния. Тогда код
для обработчика события AfterPost будет выглядеть так:
void __fastcall TForm2::Table1AfterPost(TDataSet *DataSet)
{
if (FbUpdateMode)
FnNumUpdates++;
else
FnNumAdds++;
UpdateStatusBar;
}
Теперь можно добавлять, изменять и удалять записи, наблюдая на
панели состояния количество изменений, которые внесены в базу данных.
Проверка данных
При любом обсуждении приложений, работающих с БД, неизбежно
поднимается вопрос проверки целостности данных (data integrity).
20
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Целостность данных означает, что данные в базе корректны и представлены в корректном формате. В рассмотренном выше примере, например, нельзя позволить пользователю вводить буквы или знаки препинания
в поле ZIP-кода (почтового индекса), несмотря на то, что поле ZIP-кода
хранится в виде строки символов, т. к. в действительности оно представляет собой число. По этой причине нужно иметь возможность проверить
значение на допустимость. Другие поля в базах данных могут требовать и
других, специальных, проверок.
С точки зрения проверки данных поздно что-либо с ними делать, когда запись уже внесена в базу данных. Эта информация нужна до того, как
запись окажется на диске. Для этого служат события Beforexxx (где на
месте xxx — Insert, Delete или Post). Подсистема работы с базами данных
CBuilder сгенерирует событие BeforePost до того, как запись будет внесена
в базу данных, и здесь есть возможность проверить введенные данные перед тем, как разрешить дальнейшее прохождение процесса. Если проблем
не возникло, просто разрешается продолжение процесса с его обработкой
по умолчанию (которая состоит в физическом занесении записи обратно в
файл базы данных). С другой стороны, если проблемы с обработкой данных в записи возникли, нужно остановить процесс, не дав ему осуществиться до конца, для чего воспользоваться методом Abort (прервать). Это
можно сделать, записав в обработчик события BeforePost:
void __fastcall TForm2::Table1BeforePost(TDataSet *DataSet)
{
// Сначала проверим, введено ли значение ZIP-кода
if (Table1ZIPCODE->Text.IsEmpty())
{
MessageBox(NULL,"Необходимо ввести ZIP-код!", "Ошибка",MB_OK);
Abort();
return;
}
// Удостоверяемся, что для ZIP-кода введено числовое значение
std::string s = Table1ZIPCODE->Text.c_str();
for (int i=0; i<s.size(); ++i)
{
if (!isdigit(s[i]))
{
MessageBox(NULL,"ZIP-код должен иметь числовое значение!",
"Ошибка",MB_OK);
Abort();
return;
}
}
// Все в порядке, разрешаем прохождение процесса записи в БД
}
Для компиляции приведенного кода следует включить <string.h> в
начало исходного файла для получения определения класса string STL.
Проверка любых других полей на соответствие данных может быть
осуществлена тем же путем. Например, проверка при удалении может
21
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
производиться
BeforeDelete.
в
совершенно
аналогичном
обработчике
события
SQL-ОРИЕНТИРОВАННЫЙ ДОСТУП
Таблицы являются гибкими и легкими в применении компонентами
доступа, достаточными для многих приложении СУБД. TTable возвращает
все строки и столбцы единственной таблицы, если доступ не ограничивается установкой интервалов и фильтров. Компоненты запросов предоставляют разработчикам альтернативные возможности. TQuery обеспечивает
доступ к нескольким таблицам одновременно и способен адресовать некоторое подмножество записей. Вид возвращаемого набора данных зависит
от формы запроса, который может быть либо статическим, когда все параметры запроса задаются на стадии проектирования, или динамическим,
когда параметры определяются во время выполнения программы.
Указанные действия записываются и реализуются на стандартизованном языке структурированных запросов SQL (Structured Query
Language), принятом большинством серверов реляционных БД, таких как
Sybase, Oracle, InterBase и SQL Server. CBuilder передает запросы серверу,
который интерпретирует их и возвращает результаты приложению.
Компонент TQuery, как и компонент TTable, обладает всеми свойствами компонента TDataSet [4]. Следует отметить, что здесь указывается
только псевдоним базы данных, а какие таблицы из нее будут использованы, определяется в тексте запроса. Тексты запросов, которые требуется передать базе данных, размещаются в свойстве SQL объекта TQuery, представляющем собой список строк.
Создание статического запроса
Лабораторная работа № 6
Создадим форму со статическим запросом к таблице EMPLOYEE
всей информации о служащих, зарплата которых превышает заданную величину. Порядок действий должен быть следующим:
1. Поместить TQuery на форму (или в модуль данных).
2. Установить псевдоним адресуемой базы данных сервера в свойстве DatabaseName (в данном случае – BCDEMOS локальной демонстрационный базы данных, содержащей, в частности, таблицу служащих некоторого предприятия).
3. В свойстве SQL ввести команду
SELECT * FROM EMPLOYEE WHERE Salary>40000
и нажать кнопку ОК.
22
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
4. Поместить на форму (в модуль данных) TDataSource и установить
свойство DataSet в Queryl.
5. Поместить на форму TDBGrid и установите ее свойство DataSource
в DataSourcel.
6. Установить в true свойство Active для запроса Queryl, чтобы сразу
отобразить данные.
Теперь добавим возможность реализации введенного пользователем
запроса. Добавим на форму компоненты TButton и TMemo. Приведенный
ниже код показывает обработчик события ButtonlClick, реализующий ввод
запроса пользователем при нажатии кнопки на форме. Свойство SQL имеет объектный тип TStrings. Введенная команда SQL записывается в строчный массив свойства Lines компонента TMemo. Результаты запроса можно, как и в предыдущем примере, отобразить на сетке.
void_fastcall TForm1::ButtonlClick(TObject *Sender)
{
// Проверить, введена ли какая-то строка в Memol
if (strcmp(Memol->Lines->Strings[0].c_str(), "") == 0)
{
MessageBox(0, "No SQL Statement Entered", "Error", MB_OK) ;
return;
}
else
{
// Деактивировать предыдущий запрос, если он имел место
Queryl->Close ();
// Очистить свойство SQL от предыдущего запроса
Queryl->SQL->Clear () ;
// Присвоить введенный в Memol текст свойству SQL
Queryl->SQL->Add(Memol->Lines->Strings[0].c_str()) ;
try
{
Queryl->0pen(); // выполнить команду SQL }
catch(EDBEngineError* dbError) // обработка ошибок BDE
{
for (int i=0; i<dbError->ErrorCount; i++)
MessageBox (0, dbError[i].Message.c_str(), "SQL Error", MB_OK);
}
}
}
Задание. Создайте приложение, которое позволяло бы выбирать по
желанию пользователя способ доступа к данным (TTable или TQuery).
Генератор запросов
Если по каким-либо причинам свойство SQL компонента TQuery
неудобно определять непосредственно в редакторе свойств, следует воспользоваться генератором запросов (Visual Query Builder, или VQB). Генератор запросов строит запросы путем последовательного добавления вы23
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
ражений, таблиц, полей и отношений, пока не получится требуемый результат.
VQB можно вызвать, выбирая компонент TQuery и вызывая контекстное меню, из которого следует выбрать опцию Query Builder.
Замечание. VQB входит в комплект поставки не всех версий CBuilder
или может быть не установлен. В этом случае в контекстном меню не будет соответствующей опции.
После выбора VQB появится диалоговая панель Databases, позволяющая выбрать БД и осуществить соединение с ней. После установления
соединения выводится окно VQB и диалоговая панель для выбора таблиц,
используемых в запросе. Панель инструментов VQB позволяет выбирать
операции, которые можно выполнить при создании, тестировании и просмотре текста запроса.
Для внесения одной или более таблиц в запрос следует:
1) если диалоговая панель Add Table не присутствует на экране, щелкнуть кнопкой Table на панели инструментов, чтобы вывести ее на экран;
2) выбрать имя таблицы из списка таблиц в диалоговой панели и
щелкнуть на кнопке Add;
3) повторить шаг 2, пока все требуемые таблицы не будут внесены в
запрос, и затем нажать кнопку «Close».
Чтобы внести колонку одной из таблиц в запрос, нужно выбрать имя
колонки и затем перетащить эту колонку и поместить на таблицу в нижней
части окна либо дважды щелкнуть на имени колонки. Для выбора всех полей таблицы следует перетащить в нижнюю часть окна значок *, находящийся над списком полей таблицы.
Чтобы скомбинировать информацию из нескольких таблиц, нужно
определить, как будут соединяться разные таблицы. С помощью VQB
можно определить колонки, имена которых служат для связи таблиц: нужно выбрать имя колонки, по которой осуществляется межтабличная связь,
в одной из связываемых таблиц, нажать левую клавишу мыши и переместить курсор (он изменит форму) на имя соответствующей колонки другой
таблицы. В результате в рабочем пространстве запроса образуется линия,
связывающая колонки этих двух таблиц. Критерий соединения таблиц
можно просмотреть или отредактировать, дважды щелкнув на линии соединения в верхней части окна VQB.
Для определения критерия отбора для запроса используется строка
Criteria таблицы в нижней части окна генератора запросов. Она допускает
любые выражения запроса, являющиеся допустимыми с точки зрения
предложения WHERE оператора SQL. Выражения в строке Criteria являются условиями AND. Условия OR вводятся как выражения в строку OR
(ниже строки Criteria).
Результаты можно отсортировать в восходящем (ascending) или нисходящем (descending) порядке для выбранной колонки. Для этого следует
24
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
поместить указатель мыши на колонке около строки Sort и выбрать порядок сортировки из контекстного меню.
Для группировки результатов запроса используется строка Option.
Условия для результатов группировки можно определить с использованием строки Group Condition, что эквивалентно внесению выражения с предложением HAVING в SQL-операторе SELECT, использующем предложение GROUP BY.
VQB позволяет также определить выражения как часть запроса. Для
создания вычисляемого поля следует выбрать кнопку Expression на панели
инструментов. Диалоговая панель Expression позволяет использовать в запросах арифметические операции, имена колонок и составные выражения,
такие как avg, count, min, max и sum. Можно редактировать вручную или
строить выражения, используя блок редактора Expression.
Можно выполнить запрос, сгенерированный VQB, нажав кнопку Run
на панели инструментов. Результаты запроса отобразятся на экране в диалоговой панели Result Window, которая позволяет убедиться, что все требуемое было определено корректно.
Текст запроса можно проверить в окне SQL Statement, нажав кнопку
SQL на панели инструментов. При внесении изменений в запрос содержимое окна SQL Statement редактируется автоматически.
Для завершения работы VQB следует нажать кнопку завершения на
инструментальной панели, после чего свойству SQL обрабатываемого
компонента TQuery будет присвоен сгенерированный текст SQL-запроса.
Задание. Применить генератор запросов.
Динамические запросы
Варианты использования запросов, рассмотренные выше, имеют определенные недостатки. В случае запроса, определенного на этапе разработки, нет возможности его изменения во время выполнения, а в случае
редактируемого запроса требуется пользователь, хорошо знакомый с SQL.
Решать эти проблемы как раз и призваны динамические запросы.
CBuilder дает возможность конструирования команды SQL динамического запроса с параметрами. Для того чтобы указать нужный параметр
динамического запроса, используется символ двоеточия перед именем этого параметра. Например, параметр номера служащего в таблице employee
идентифицируется следующей командой:
SQL: SELECT * FROM employee WHERE EmpNo = :EmpNo.
Увидеть или поменять атрибуты выбранного параметра можно посредством диалогового редактора, который открывается двойным щелчком
мыши в графе значений этого свойства. Нажатие кнопки ОК подготавливает SQL-сервер к запросу и вызывает попытку его выполнения на стадии
проектирования приложения.
25
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Свойство Params компонента TQuery позволяет специфицировать
имена, типы и начальные значения параметров запроса и содержит указатель на объект типа TParams. Изменить значение параметра во время выполнения программы можно по индексу в массиве Items объекта типа
TParams, например:
Queryl->Params->Items[0]->AsInteger = 4;
или по имени параметра, с помощью метода ParamByName:
Queryl->ParamByName ("FirstName") ->AsString = "John";
Лабораторная работа № 7
Рассмотрим пример использования метода ParamByName во время
исполнения программы. В результате выполнения запроса должен быть
выведен список служащих с заданным именем. Параметр имени служащего FirstName идентифицируется командой SQL:
SELECT * FROM EMPLOYEE WHERE FirstName = :FirstName
Разместим на форме компоненты TDataSourse, TQuery, TDBGrid,
TButton, TEdit (для задания имени работника), а также выполним необходимые для их использования действия. Затем запишем:
void_fastcall TForm1::Button1Click(TObject *Sender)
{
// Деактивировать предыдущий запрос, если он имел место
Queryl->Close();
if (!Queryl->Prepared)
Queryl->Prepare(); // подготовить запрос
// Заменить значение параметра на введенное пользователем
Queryl->ParamByName("FirstName")->AsString =
Editl->Text.c_str() ;
try
{
Query 1 ->0pen(); // выполнить команду SQL }
catch(EDBEngineError* dbError) // обработка ошибок BDE
{
for (int i=0; i<dbError->ErrorCount; i++)
MessageBox(0, dbError[i].Message.c_str(), "SQL Error", MB_OK) ;
}
}
Замечание. Обработчик события прежде всего обращается к методу
подготовки запроса Prepare, посылая команду SQL-серверу. Сервер выделяет ресурсы и оптимизирует динамический запрос до первого исполнения. Все, что нужно в дальнейшем, – подставлять новые значения параметров и выполнять команду запроса с помощью метода Open.
В рассмотренных примерах все запросы представляли собой команду
SELECT. Результат такого запроса рассматривается как набор данных (как
при работе с таблицей). Существуют другие команды SQL, например, команда UPDATE, которая обновляет содержимое некоторой записи, но не
26
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
возвращает никакого результата. Для исполнения сервером таких запросов
следует использовать метод ExecSQL вместо метода Open.
Задание. Создайте приложение для произвольного конструирования
простого запроса, содержащего логическое выражение.
ХРАНИМЫЕ ПРОЦЕДУРЫ
Хранимая процедура представляет собой инкапсуляцию команд и
данных в некотором мета-объекте базы данных удаленного сервера. Компонент TStoredProc позволяет выполнить часто повторяющиеся процедуры
с интенсивными вычислениями, хранимые на сервере, и передать результаты приложению клиента. Операции над большими группами строк в таблице БД, агрегатные или математические функции — подходящие кандидаты для хранимых процедур. Использование хранимых процедур может
заметно улучшить производительность приложения.
Процедура проектирования приложения с TStoredProc аналогична
той, которая использовалась для отображения результатов запроса:
1) установить псевдоним адресуемой БД сервера в свойстве
DatabaseName;
2) поместить на форму TDataSource и установить DataSet =
= StoredProc1;
3) поместить на форму TDBGrid и установить DataSource =
= DataSource1;
4) поместить TStoredProc на форму и задать StoredProcName;
5) установить Active = true для StoredProc1, чтобы сразу отобразить
результаты в сетке;
6) открыть редактор параметров, ввести их значения и нажать кнопку
ОК.
Лабораторная работа № 8 (самостоятельная)
Реализовать приложение, вычисляющее среднеквадратичное отклонение значений по большой выборке записей.
УТИЛИТЫ
Рассмотрим некоторые утилиты, поставляемые с системой CBuilder.
Одна из них — BDE, Borland Database Engine, которая представляет
собой интерфейс со многими стандартными базами данных. BDE умеет
напрямую работать с базами данных dBase и Paradox, а также Interbase.
Кроме того, в некоторых версиях поставки CBuilder (Professional и выше)
BDE может использоваться также для работы с базами данных ODBC.
Обычно инсталляция BDE происходит при установке CBuilder, однако это
27
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
можно сделать и в любой другой момент (из каталога BDE на компактдиске с системой CBuilder).
Если разработанная программа использует BDE и ее нужно устанавливать на компьютер пользователя, рекомендуется использовать программу InstallShield, которая поставляется вместе с версией CBuilder
Professional Edition (и выше). Тогда нужно лишь указать имя исполняемого
файла разработанной программы, а затем выбрать файлы, которые требуется поставлять вместе с этим приложением. InstallShield выполнит все остальное, включая установку всех разрешенных к распространению файлов
систем BDE и IDAPI, которые дают программе доступ к БД.
Главное, что дает BDE, — работа с псевдонимами, что позволяет не
заботиться о типе и местонахождении файлов таблиц БД. В системе BDE
есть три инструмента, про которые стоит коротко рассказать: конфигуратор BDE (BDE Configuration), Database Desktop и проводник баз данных
(Database Explorer), поставляемый с CBuilder. Дадим краткое описание каждого.
Программа конфигурирования BDE позволяет определять псевдонимы, изменять их свойства и работать с местами расположения и разрешениями доступа к базам данных в системе.
Database Desktop — наиболее удобный инструмент для разработки
новых баз данных, тестирования запросов, написания выражений SQL и
просмотра данных, вводимых в систему. Утилиту Database Desktop можно
запустить из меню CBuilder.
Последняя утилита, на которую стоит обратить внимание, —
Database Explorer. Она позволяет легко и быстро просматривать структуру
базы, включая все имена таблиц, индексы, поля, поля проверки целостности (validity checks), поля проверки перекрестных ссылок (referential
integrity checks) и многое другое для баз данных ODBC, Paradox и dBase.
ЗАДАНИЯ
1. Разработать БД:
поликлиника; отдел кадров; кондитерская фабрика; кафедра вуза; учет вещественных доказательств; магазин канцтоваров; патентное бюро; касса
аэропорта; расчет стипендии; автосервис; цементный завод; детский сад;
фермерское хозяйство; грузоперевозки.
2. Выполнить задания из раздела «Построение SQL-запросов» в [6].
28
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
СПИСОК ЛИТЕРАТУРЫ
1. Страуструп Б. Язык программирования C++ / Б. Страуструп ; пер.
с англ. С. Анисимова, М. Кононова ; под ред. Ф. Андреева, А. Ушакова. –
3-е изд. — М. ; СПб. : Бином : Нев. диалект, 1999. — 990 с.
2. Холзнер С. Visual C++6 : учеб. курс / С. Холзнер. — СПб. : Питер,
1999. — 569 с.
3. Теллес М. Borland C++ Builder (+CD). Библиотека программиста /
М. Телес. – (http://www.piter-press.ru/lib/978531400107/).
4. Елманова Н. Работа с базами данных в Borland C++ Builder /
Н. Елманова // Компьютер-Пресс. — 1997. — № 6. — С. 122–129; № 7. –
С. 136–144.
5. Учебник по C++ Builder. – (http://www.compdoc.ru/prog/builder/builder/).
6. Разработка приложений баз данных в среде Delphi : метод. пособие к
спецкурсу «Базы данных и экспертные системы» для студентов 4 курса дневного отделения и 4 курса вечернего отделения факультета ПММ / сост. :
В.Г. Рудалев, Ю.А. Крыжановская. — Воронеж, 2002. — 59 с.
29
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
Учебное издание
ИСПОЛЬЗОВАНИЕ СРЕДЫ C++ BUILDER
ДЛЯ РАБОТЫ С БАЗАМИ ДАННЫХ
Учебно-методическое пособие для вузов
Составитель
Крыжановская Юлиана Александровна
Подписано в печать 02.04.09. Формат 60×84/16. Усл. печ. л. 1,7.
Тираж 25 экз. Заказ 144.
Издательско-полиграфический центр
Воронежского государственного университета.
394000, г. Воронеж, пл. им. Ленина, 10. Тел. 208-298, 598-026 (факс)
http://www.ppc.vsu.ru; e-mail: pp_center@ppc.vsu.ru
Отпечатано в типографии Издательско-полиграфического центра
Воронежского государственного университета.
394000, г. Воронеж, ул. Пушкинская, 3. Тел. 204-133
Документ
Категория
Информатика
Просмотров
372
Размер файла
523 Кб
Теги
среды, данных, 666, использование, базами, работа, builder
1/--страниц
Пожаловаться на содержимое документа