Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DBM_1_X1.doc
Скачиваний:
2
Добавлен:
14.11.2019
Размер:
5.12 Mб
Скачать

4.Разработка клиентского места

В данной методической разработке рассмотрены две реализации клиентского приложения на Object_Pascal и C++. Причем для сопоставимости в качестве среды разработки выбраны DELPHI6 BORLAND C++BUILDER6. Такой выбор позволил продемонстрировать реализацию клиентского приложения с использованием одной и той же объектной библиотеки, а отличия в коде связаны только с особенностью используемых языков программирования. Коды используемых процедур приводятся в виде таблицы, левая колонка которой связана с языком Object_Pascal, а правая – с C++. При выполнении курсового проекта студент может выбрать любую реализацию.

4.1 Основная экранная форма

Имеются несколько основных компонент (классов), которые используются для доступа к БД. Эти классы делятся на три группы:

  • невизуальные: TDataBase, TTable, TQuery, TField

  • визуальные: TDBGrid, TDBEdit

  • связующие: TDataSource

Первая группа включает невизуальные классы, которые используются для управления базами данных, таблицами и запросами. Эта группа сосредотачивается вокруг компонент типа TDataBase, TTable, TQuery и TField. В Палитре Компонент они расположены на странице BDE.

Вторая важная группа классов - визуальные, которые показывают данные пользователю, и позволяют ему просматривать и модифицировать их. Эта группа классов включает компоненты типа TDBGrid, TDBEdit, TDBImage и TDBComboBox. В Палитре Компонент они расположены на странице Data Controls.

Третий тип, используется для того, чтобы связать предыдущие два типа объектов. К этому типу относится невизуальный компонент TDataSource (на странице Data Access).

Рассмотрим последовательность действий построения клиентской части программы ..\PRG0\SKLAD.DPR.

Object_Pascal

Borland_C++

  1. Запустить Delphi. В результате загрузится новый проект с формой.

1.Запустить С++Builder6. В результате загрузится новый проект с формой.

  1. Выбрать набор инструментов Data Access. Перенести на форму копию объекта типа TDataBase. Настроить параметры объекта DataBase как показано ниже

2.Выбрать набор инструментов Data Access. Перенести на форму копию объекта типа TDataBase. Настроить параметры объекта DataBase как показано ниже

Параметр Login prompt должен иметь значение false. В противном случае, при любом обращении к базе данных система будет запрашивать у пользователя пароль доступа к БД. Поле отметки Keep Inactive Connection в отмеченном состоянии означает, что соединение с БД будет сохраняться даже, если ни один набор данных этой базы данных не будет открыт. В окне Parameter overrides можно переустановить параметры псевдонима БД и драйвера.

Элемент типа TDataBase создается для каждого факта соединения с отдельной базой данных. Случаи явного использования в приложении компонента TDataBase чаще всего связаны с работой в архитектуре клиент-сервер. Явно определенный в программе компонент TDataBase облегчает управление БД, создавая постоянные соединения с ней, настраивая сеанс соединения с базой данных, управляя транзакциями, создавая локальные псевдонимы BDE. Каждый набор данных, работающий с таблицами одной и той же БД, может иметь с этой базой отдельное соединение. Однако это нерационально, поскольку каждое соединение съедает системные ресурсы. Для минимизации их использования рекомендуется создавать единственное соединение с базой данных при помощи компонента TDataBase, а все наборы данных, реализующие действия над БД, соединять с этим компонентом. Соединение активизируется установкой свойства Connected в значение true. Свойство DataBaseName определяет локальный псевдоним БД, который может использоваться при доступе к БД вместо псевдонима BDE7.

  1. Доступ к конкретной таблице БД регулируется компонентом TTable из набора Data Access. Для организации доступа к таблице «Товары» необходимо переместить копию компонента TTable на экранную форму и настроить в инспекторе объектов свойства DataBaseName (установить алиас UchSklad), свойство TableName (установить TOVARY). Кроме того, установим имя Name объекта как TovaryTable

Доступ к таблице регулируется установкой значения свойства Active в true. В программном коде открытие (закрытие) таблицы осуществляется также с помощью метода TovaryTable.Open (TovaryTable.Close).

TTable представляет собой пример невизуального компонента и становится невидимым при запуске программы. Для визуализации данных таблицы и интерактивной работы с ними служит компонент TDBGrid в группе Data Controls. Связь между визуальными и невизуальными компонентами осуществляется компонентом TdataSource. Этот класс используется в качестве проводника между TTable или TQuery и компонентами, визуализирующими данные, типа TDBGrid, TDBEdit и TDBComboBox (data-aware components). В большинстве случаев, все, что нужно сделать с DataSource - это указать в свойстве DataSet соответствующий TTable или TQuery. Затем, у data-aware компонента в свойстве DataSource указывается TDataSource, который используется в настоящее время. Любая таблица может быть открыта на этапе проектирования. При этом визуальные компоненты, связанные с таблицей, отображают текущее состояние записей соответствующего набора данных, но перемещение и редактирование записей невозможны. Исключение составляет возможность перемещения текущего указателя с помощью полосы прокрутки для визуальной компоненты TDBGrid.

TDataSource также имеет свойство Enabled, и оно может быть полезно всякий раз, когда Вы хотите временно отсоединить, например, DBGrid от таблицы или запроса. Это требуется, например, если нужно программно пройти через все записи в таблице. Ведь, если таблица связана с визуальными компонентами (DBGrid, DBEdit и т.п.), то каждый раз, когда Вы вызываете метод TTable.Next, визуальные компоненты будут перерисовываться. Даже если само сканирование в таблице двух или трех тысяч записей не займет много времени, то может потребоваться значительно больше времени, чтобы столько же раз перерисовать визуальные компоненты. В случаях подобных этому, лучше всего установить поле DataSource.Enabled в False. Это позволит просканировать записи без перерисовки визуальных компонент. Такая операция может увеличить скорость в некоторых случаях в десятки и сотни раз.

Свойство TDataSource.AutoEdit указывает, переходит ли DataSet автоматически в режим редактирования при вводе текста в data-aware объекте.

Перенесем компонент TDataSource на форму и установим свойство DataSet равным TovaryTable.

4.Перенесем компонент TDBGrid на форму. Установим значение свойства DataSource равным DataSource1. Добавим на форму компонент TDBNavigator, свойство DataSource которого установим равным DataSource1. Прежде чем запустить программу добавим на форму компонент TStoredProc, свойство DatabaseName которого установим равным UchSklad, а имя процедуры StoredProcName GET_KOD_TOVAR(Напомним, что эту процедуру мы создали ранее на сервере).

Далее найдем для объекта TovaryTable событие AfterInsert и определим обработчик этого события в виде процедуры

Object_Pascal

Borland_C++8

procedure Form1.TovaryTableAfterInsert (DataSet: TDataSet);

begin

StoredProc1.ExecProc;

TovaryTable.FieldByName('Kod_Tovar').Value:=

StoredProc1.ParamByName('NR').Value;

end;

Void __fastcall TForm1::TovaryTableAfterInsert(TDataSet *DataSet)

{

StoredProc1->ExecProc();

TovaryTable-> FieldByName("Kod_Tovar")->Value= StoredProc1->

ParamByName("NR")->Value;

}

Оператор StoredProc1.ExecProc (В C++ функция StoredProc1->ExecProc();) запускает процедуру с именем GET_KOD_TOVAR на сервере. Полученный результат присваивается полю Kod_Tovar9. При помощи этой процедуры можно автоматически увеличивать значение поля Kod_Tovar на 1.

Кнопки объекта DBNavigator1 имеют слева направо следующие значения:

Первая запись

Предыдущая

Следующая

Последняя запись

Вставка записи

Удаление записи

Редактирование записи

Подтверждение редактирования

Отказ от изменений

Обновление данных

Изменив соответствующим образом список Hints у навигатора, и установив флажок на форме ShowHint в true, можно получить эти записи в качестве подсказок на экране при фокусировке мыши на соответствующей кнопке.

Аналогичным образом можно получить доступ к записям таблиц «Покупатели» и «Расход товара».

При работе с форматами данных различных регионов бывает необходимо настроить форматы дат, времени, различные разделители. Настройку можно сделать:

      1. на уровне операционной системы (через настройку свойств «языки и стандарты» панели управления)

      2. на уровне BDE (настройка параметров драйверов)

      3. на уровне клиентской части программы

Ниже приводится пример такой настройки на уровне клиентской части программы. Для этого необходимо построить обработчик события OnCreate формы в виде процедуры

Object_Pascal

Borland_C++

procedure TForm1.FormCreate(Sender: TObject);

begin

DateSeparator:='.';

ShortDateFormat:='dd.mm.yyyy';

ShortTimeFormat:='hh:mm:ss';

end;

void __fastcall TForm1::FormCreate(TObject *Sender)

{

DateSeparator='.';

ShortDateFormat="dd.mm.yyyy";

ShortTimeFormat="hh:mm:ss";

}

Системная переменная (модуля SysUtils) DateSeparator описывает разделитель, переменные ShortDateFormat и ShortTimeFormat задают форматы дат и времени. Процедура отрабатывает при запуске программы при создании формы.

В качестве примера динамического перепрограммирования свойств объектов приведем пример обслуживания одним навигатором двух таблиц «Товары» и «Покупатели». Как уже упоминалось выше, в навигаторе свойство DataSource необходимо настроить на имя компонента TDataSource, связывающий навигатор с определенной таблицей. Изменяя динамически эту связь можно одним навигатором обслуживать различные таблицы.

Перенесем на форму копию компонента Tlabel и напишем обработчик события OnEnter для объекта DBGrid1.

Object_Pascal

Borland_C++

procedure TForm1.DBGrid1Enter(Sender: TObject);

begin

DBNavigator1.DataSource:= DataSource1;

DBNavigator1.Enabled:=True;

Label1.Caption:='Товары';

end;

void __fastcall TForm1::DBGrid1Enter(TObject *Sender)

{

DBNavigator1-> DataSource=DataSource1;

DBNavigator1->Enabled=True;

Label1->Caption="Товары";

}

Аналогичную процедуру

Object_Pascal

Borland_C++

procedure TForm1.DBGrid2Enter(Sender: TObject);

begin

DBNavigator1.DataSource:= DataSource2;

DBNavigator1.Enabled:=True;

Label1.Caption:='Покупатели';

end;

void __fastcall TForm1::DBGrid2Enter(TObject *Sender)

{

DBNavigator1-> DataSource=DataSource2;

DBNavigator1->Enabled=True;

Label1->Caption="Покупатели";

}

будем использовать как обработчик события OnEnter для объекта DBGrid2.

Запустив программу можно убедиться, что любое переключение между объектами Grid для таблиц «Товары» и «Покупатели» изменяет состояние метки Label1, которое показывает, какой таблицей в настоящий момент управляет навигатор.

Для таблицы «Расход товара» построим собственный навигатор, используя методы объекта TTable.

В частности, если на форме имеется объект Table1, то методы Table1.First, Table1.Last, Table1.Next, Table1.Prior – осуществляют соответственно переход к первой, последней, следующей и предыдущей записи.

Добавление новой записи осуществляется с использованием метода Table1.Add или Table1.Insert. Отличие метода Table1.Add от Table1.Insert состоит в том, что в первом случае запись добавляется в конец таблицы, а во втором – запись вставляется непосредственно перед записью, на который указывает курсор. Метод Table1.Delete удаляет текущую запись.

Метод Table1.Edit переводит таблицу в режим редактирования. Методы Table1.Post и Table1.Cancel означают соответственно подтверждение или отказ от сделанных изменений. Метод Table1.Refresh обновляет содержимое таблицы на форме. Необходимо помнить, что всякий раз, когда происходит смещение указателя с текущей записи, в таблице автоматически будут сохранены введенные данные. Это означает, что вызовы First, Next, Prior и Last всегда выполняют Post, если Вы находились в режиме редактирования. Если Вы работаете с данными на сервере и транзакциями, тогда правила, приведенные здесь, не применяются. Тем не менее, даже если Вы не работаете с транзакциями, Вы можете все же отменить результаты вашего редактирования в любое время, до тех пор, пока не вызвали напрямую или косвенно метод Post. Например, если Вы перевели таблицу в режим редактирования, и изменили данные в одном или более полей текущей записи, Вы можете всегда вернуть текущую запись в исходное состояние вызовом метода Cancel.

Наборы данных могут находиться в определенных состояниях. Состояние набора определяется свойством State. Это свойство доступно только для чтения и используется при выполнении операций над записями таблицы (некоторые операции над набором разрешены только в определенных состояниях). Для перевода набора данных в требуемое состояние используются специальные методы.

Перечислим основные состояния набора данных:

dsInactive – набор данных закрыт;

dsBrowse – набор данных находится в состоянии просмотра. Переход в этот режим происходит из режимов dsEdit и dsInsert при вызове одного из методов Post или Cancel.

dsEdit – набор данных находится в состоянии редактирования. Переход в этот режим происходит из режимов dsBrowse при вызове метода Edit.

dsInsert – набор данных находится в состоянии добавления новой записи. Переход в этот режим происходит из режимов dsBrowse при вызове одного из методов Insert, InsertRecord, Append или AppendRecord.

dsSetKey – режим поиска записей, удовлетворяющих некоторому условию. Переход в этот режим происходит из режимов dsBrowse при вызове одного из методов SetKey, FindKey, GotoNearest или FindNearest. Возможен только для компоненты типа TTable, для компоненты TQuery отбор записей осуществляется средствами языка SQL.

dsOpening – набор данных находится в открытом состоянии.

Построим на форме кнопки «Следующая»(Next) и «Вставить»(Add), выбирая компонент Button из палитры Standart. В обработчик события OnClick первой кнопки вставим процедуру10

Object_Pascal

Borland_C++

procedure TForm1.NextClick(Sender: TObject);

begin

IF NOT RasxodTable.EOF THEN

RasxodTable.Next

ELSE Next.Enabled:=False;

end;

void __fastcall TForm1::NextClick(TObject *Sender)

{

if (!RasxodTable->Eof)

RasxodTable->Next();

else Next->Enabled=False;

}

а в соответствующий обработчик второй кнопки процедуру

Object_Pascal

Borland_C++

procedure TForm1.AddClick(Sender: TObject);

begin

RasxodTable.Insert;

end;

void __fastcall TForm1::AddClick(TObject *Sender)

{

RasxodTable->Insert();

}

Задача: Построить код для своего навигатора таблицы «Расход товара», смоделировав работу навигатора из визуальной библиотеки компонент.

Выше уже отмечалось, что таблицы «Товары» и «Расход товара» связаны по формулам:

  • Стоимость купленного товара:=Количество купленного товара * цена единицы товара,

  • Количество товара на складе:= Количество товара на складе – Количество купленного товара.

При этом заметим, «Количество купленного товара» и «цена единицы товара» («Количество товара на складе») лежат в разных таблицах. Решением второй задачи мы уже занимались.

Для первого случая поступим следующим образом:

  • Во первых, свяжем эти таблицы операционной связью (Relation, Link, Master-Detal) так, чтобы таблица «Товары» всегда была позиционирована на том товаре, который продается согласно текущей строке таблицы «Расход товара». Это позволит «всегда иметь под рукой» цену продаваемого товара.

Для этого установим у объекта TovaryTable (типа TTable) значение свойства MasterSource равным DataSource3 (который управляет таблицей Rasxod через объект RasxodTable) и значение свойства MasterFields (после щелчка на кнопку «...» появится окно редактора связей, в котором надо выбрать ключи связи KOD_TOVAR->KOD_TOVAR). Объявленная связь сразу проявится – DBGrid1 будет показывать только строку таблицы «Товары», соответствующую текущей строке в «Расход товара»11.

Аналогично можно связать ведомую (Detal-)таблицу «Покупатели» с ведущей (Master-)таблицей «Расход товара».

  • Теперь для события OnDataChange объекта DataSource3 напишем обработчик12

Object_Pascal

Borland_C++

procedure TForm1.DataSource3DataChange

(Sender: TObject; Field: TField);

var ss:INTEGER;

begin ss:= RasxodTable.FieldByName('Kolvo').Value*

TovaryTable.FieldByName('Zena').Value;

if (RasxodTable.FieldByName('Stoim').Value<>ss)AND

((RasxodTable.State=dsEdit)OR

(RasxodTable.State=dsInsert))

then RasxodTable.FieldByName('Stoim').Value:=ss;

end;

void __fastcall TForm1::DataSource3DataChange(TObject *Sender,

TField *Field)

{ int ss;

ss=RasxodTable-> FieldByName("Kolvo")-> AsInteger * TovaryTable1-> FieldByName("Zena")-> AsInteger;

if ((RasxodTable-> FieldByName("Stoim")-> Value!=ss)&&

((RasxodTable->State== dsEdit) ||(RasxodTable-> State==dsInsert)))

RasxodTable-> FieldByName("Stoim")-> Value=ss;

}

При этом естественно значение свойства ReadOnly столбца Stoim объекта DBGrid3 положить равным True, чтобы запретить независимые корректировки этого реквизита. С этой целью необходимо дважды щелкнуть мышью на объекте DBGrid3, вызвать редактор столбцов и манипулируя левой кнопкой мыши получить доступ ко всем столбцам, в появившемся списке выбрать столбец, характеризующий стоимость и в свойстве ReadOnly выбрать значение True.

  • Остается еще один случай, в котором не обеспечено корректное обновление значение поля «стоимость» - при изменении цены товара в таблице «Товары». Для этого добавим в БД триггер:

CREATE TRIGGER AU_TOVARYI FOR TOVARY AFTER UPDATE POSITION 2

AS BEGIN

IF (OLD.ZENA <> NEW.ZENA) THEN

UPDATE RASXOD SET STOIM=NEW.ZENA*KOLVO

WHERE KOD_TOVAR = OLD.KOD_TOVAR; END

Появление значения OLD.KOD_TOVAR (а не NEW.KOD_TOVAR)в строке условия отбора оператора UPDATE вызвано необходимостью корректно обрабатывать ситуацию, когда одновременно меняются код товара и его цена. это означает, что системное каскадное обновление выполняется после выполнения триггера AU_TOVARYI, а не до (как казалось...).

Теперь установим контроль условия KOLVO>=0 – обработчик события OnValidate поля Kolvo объекта RasxodTable:

Object_Pascal

Borland_C++

procedure TForm1.RasxodTableKOLVOValidate(Sender: TField);

begin

if RasxodTable.FieldByName('Kolvo'). AsInteger<0 then

raise Exception.Create('"Количество" должно быть неотрицательным')

end;

Здесь raise - оператор языка Object Pascal порождающий исключительную ситуацию (принудительное событие «ошибка»), Exception – класс исключительных ситуаций (определенный в модуле SysUtils), Create – конструктор объектов этого класса.

void __fastcall TForm1::RasxodTableKOLVOValidate(TField *Sender)

{

if(RasxodTable-> FieldByName("Kolvo")->AsInteger<0)

throw Exception("<Количество> должно быть неотрицательным");

}

Таким способом порожденная в OnValidate исключительная ситуация не просто выдает сообщение, но и блокирует подтверждение введенного значения поля.

Прежде чем двигаться дальше, полезно посмотреть поведение программы в действии:

  • Как отрабатывает каскадное обновление таблицы «Расход товара» при удалении строки и изменении кода товара в таблице «Товары». Аналогично, для таких же операций с таблицей «Покупатели», ведь реализация каскадного обновления в этих двух случаях разная.

  • Как отрабатывает контроль ограничений целостности в таблице «Расход товара» при изменении кодов товара или покупателя на отсутствующие в родительских таблицах.

  • Как отрабатывает контроль условия ZENA>=0 и условия KOLVO>=0.

Обратите внимание: реакция на нарушение первого условия появляется только после попытки покинуть текущую строку таблицы, а для второго условия реакция почти мгновенная – программа не позволяет покинуть поле.

Это связано с тем, что второе условие контролирует Delphi-программа, причем именно в момент выхода из поля13. А первое условие контролирует InterBase SQL-сервер, причем только после попытки покинуть текущую строку таблицы – только в этот момент Delphi-программа подтверждает изменения (вызывая метод Post) и посылает запрос InterBase SQL-серверу на проведение соответствующих изменений в реальной таблице.

  • Как отрабатывает перерасчет «стоимости» при изменении вместе и по отдельности «количества» и «кода товара» в таблице «Расход товара», а также изменении цены товара в таблице «Товары».

  • Как отрабатывает перерасчет «количества на складе» при таких же изменениях в таблице «Расход товара». И как не выполняется этот перерасчет при изменении «кода товара» в таблице «Товары» и каскадном его изменении в таблице «Расход товара».

  • Как отрабатывает перерасчет «количества на складе» при удалении и добавлении строк в таблице «Расход товара». И как при добавлении отрабатывает генератор «кода покупки».

Теперь внесем в нашу программу еще несколько изменений. ..\PRG1\SKLAD.DPR

Объявленная нами связь «Detal-ведомая -> Master-ведущая» для таблиц TOVARY->RASXOD ограничила область видимости в Grid таблицы «Товары»14. Пока мы работаем в Grid таблицы «Расход товара» это возможно даже и очень удобно. Но когда мы переключаемся на Grid таблицы «Товары» хотелось бы видеть весь список товаров. Для устранения этих проблем:

  • Поместим на экранную форму еще один объект типа TTable, управляющий таблицей TOVARY, и объект типа TDataSource, управляющий ее связью с объектом DBGrid1.

Это легче сделать копированием – щелчок на копируемом объекте, CTRL+C, CTRL+V и мышкой переместить выделенную копию «в сторонку» (осторожно! копия получается точно наложенной на оригинал, но при её перемещении оригинал останется на месте).

  • Установим имя Name TovaryTable1 у нового объекта типа TTable, а у нового объекта типа TDataSource оставим имя DataSource4, предложенное системой, и на всякий случай проверим, что DataSource4 действительно ссылается (в смысле DataSet=) на TovaryTable1. Теперь разграничим функции объектов TovaryTable и TovaryTable1: пусть за связь Master-Detal с таблицей «Расход товара» отвечает TovaryTable1, а за остальное – TovaryTable.

  • У объекта TovaryTable: удалим значения свойств MasterSource, MasterFields и IndexFieldName.

  • У объекта TovaryTable1: удалим вызов обработчиков событий AfterInsert и AfterPost (но не сами процедуры обработки, т.к. они вызываются в объекте TovaryTable).

  • У объекта DataSource3 (связь с таблицей «Расход товара») внесем изменение в обработчик события OnDataChange: в процедуре DataSource3DataChange заменим

TovaryTable.FieldByName('Zena') на TovaryTable1.FieldByName('Zena').

  • Теперь обеспечим переключение так, чтобы таблицей «Товары» управлял объект TovaryTable, когда курсор находится в DBGrid1 таблицы «Товары», и объект TovaryTable1, когда курсор находится в DBGrid3 таблицы «Расход товара».

Для этого внесем изменения в текст обработчика события OnEnter объекта DBGrid1: в процедуру DBGrid1Enter15 (в начало) добавим

Object_Pascal

Borland_C++

DBGrid1.DataSource:=DataSource1;

IF DataBase1.Connected then

TovaryTable.Refresh;

DBGrid1->DataSource= DataSource1;

if (Database1->Connected) TovaryTable->Refresh();

Далее поправим обработчик события OnEnter объекта DBGrid3: в процедуру DBGrid3Enter (в начало) добавим

Object_Pascal

Borland_C++

DBGrid1.DataSource:=DataSource4;

TovaryTable1.Refresh;

DBGrid1->DataSource= DataSource4;

TovaryTable1->Refresh();

Аналогичные преобразования надо провести для таблицы «Покупатели» и её связи с таблицей «Расход товара». Теперь мы будем видеть полный список товаров и покупателей в своем «окне просмотра», а находясь в окне просмотра «Расход товаров» будем видеть информацию только о текущем товаре и покупателе. Причем сохранится правильность расчета стоимости продажи, которая существенным образом основана на связи Master-Detal.

Мы убедились, что при добавлении записей генераторы правильно формируют коды соответствующих элементов таблиц. Можно заметить, что значение полей, описывающих эти коды и необходимых для обеспечения уникальности записей, не носят содержательный характер, и могут быть исключены из состава столбов визуальной компоненты TDBGrid. Также желательно наименования столбцов таблиц выводить на русском языке. Для исключения столбца из состава столбцов визуальной компоненты необходимо выбрать мышью объект DBGrid1, в инспекторе объектов найти свойство Columns, открыть окно редактирования столбцов, через контекстное меню создать список, включающий все поля таблицы (далее можно удалить ненужные столбцы из списка). Каждый столбец, являясь объектом, имеет ряд свойств. Для изменения наименования столбца необходимо исправить для каждого поля свойство Caption, входящее в список подсвойств свойства Title.

Записи в Таблице «Расход товара» не содержат наименований товаров и покупателей, а содержат только коды этих реквизитов. Поскольку код товара не несет содержательной информации, а конечный пользователь привык работать с наименованием товара, желательно при показе таблицы «Расход товара» выводить на экран не коды товара и покупателя, а их наименования. Этого можно достичь, используя поля выбора данных(LookUp-поля). Создадим LookUp-поле для наименования товара.16 Выберем мышью иконку компоненты Ttable для таблицы «Расход товара» и двойным щелчком вызовем пустой список полей таблицы. Вызвав правой кнопкой мыши контекстное меню, выберем режим добавления всех полей, а также режим добавления нового поля. Появившуюся форму необходимо заполнить, как показано ниже

На данном экране описана LookUp-связь по ключевому полю KOD_TOVAR с таблицей «Товары». В результате всех этих действий в таблице «Расход товара» образуется новое текстовое поле TOVAR, которое связано по полю KOD_TOVAR с соответствующим полем таблицы «Товары». Совершенно аналогично поступим с полем POKUP. В столбцах компоненты DBGrid3 появляются элементы ComboBox (с наименованием товара и покупателя) через которые можно осуществить выбор значения соответствующего реквизита.

Набор значений полей может быть организован также через компоненты DBText, DBEdit, DBMemo, DBListBox, DBComboBox, DBCheckBox, DBRadioGroup, DBLookUpComboBox и пр. В каждом из этих элементов необходимо настроить свойства DataSource и DataField. 17

1 ) Параметр CHARACTER SET WIN1251 можно опустить, он будет устанавливаться по умолчанию для символьных полей, т.к. ссылка на эту кодировку символьных данных была задана при создании базы данных. Опускать значение параметра COLLATE не рекомендуется, по умолчанию оно может установиться совсем не так, как ожидалось.

2 При необходимости свойства поля таблицы, описанные с использованием типа KEY_TYPE, могут быть изменены при создании таблицы. Для этого после описания типа необходимо описать необходимые значения параметров.

3 Такая ситуация называется нарушением условия целостности базы данных.

4 Рекомендуется указывать явным образом мнемоничное имя вводимого условия (CONSTRAINT). В приведенном случае - TOV_RASH. В этом случае при возникновении исключительных ситуаций сервер ссылается на это условие по данному имени. Если имя не указать, то сервер сам генерирует имя. Появление пользовательских наименований в сообщениях сервера облегчает анализ исключительной ситуации.

5 Вообще говоря, можно было при проектировании базы данных не включать поле «Стоимость купленного товара» в таблицу RASXOD, поскольку при необходимости эти значения вычисляются с использованием данной формулы. В нашем примере данное поле присутствует из желания продемонстрировать требования к целостности базы данных и механизм поддержки целостности.

6 Товар был куплен по ошибке и обменен на другой товар

7 При использовании в DataBaseName алиаса, определенного в администраторе (поскольку алиас является внешним и доступен через администратор)система, при любом обращении к базе данных будет запрашивать у пользователя пароль доступа к БД. Поэтому рекомендуется выбирать локальный псевдоним отличный от внешнего алиаса.

8 Внимание! При переносе кода в С++ необходимо учитывать отличия в синтаксисе, которые связаны с доступом к полям структуры, оформлением наименований полей (строки в С++ оформляются двойными кавычками, символы - одинарными) и традиционными различиями оформлений оператора присваивания.

9 Ключевое поле Kod_Tovar не является содержательным и введено в таблицу для решения задач, связанных с организацией базы данных. Поэтому конечный пользователь не должен иметь доступ к этому полю, и его заполнение должно происходить в автоматическом режиме.

10 Навигация по таблице, вообще-то говоря, разрешена лишь в определенных состояниях (например, не разрешена в режиме редактирования или вставки записи). Эти состояния можно отследить, проверяя значение свойства State. Более правильным является код:

Object_PascalBorland_C++procedure TForm1.NextClick(Sender: TObject);

begin

IF RasxodTable.State = DsBrowse THEN

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]