Delphi 3 и создание приложений баз данных

       

в состав первичного или уникального


30. Использование генераторов

Часто в состав первичного или уникального ключа входят цифровые поля, значения которых должны быть уникальны, то есть не повторяться ни в какой другой записи таблицы. В одних случаях такое значение является семантически значимым и формируется пользователем по определенному алгоритму -например, номер лицевого счета в банке. В других случаях лучше предоставить выработку такого значения приложению или серверу БД.

Для локальных СУБД (например, Paradox) для названной цели применяются автоинкрементные поля. При добавлении новой записи BDE автоматически устанавливает значение автоинкрементного поля так, чтобы оно было уникальным и не совпадало со значением данного автоинкрементного поля в других записях таблицы - не только существующих, но и удаленных. Иными словами, ранее использовавшееся значение автоинкрементного поля, даже если оно освободилось в результате удаления записи, никогда не назначается вновь. Изменить значение автоинкрементного поля нельзя.

В InterBase отсутствует аппарат автоинкрементных столбцов. Вместо этого для установки уникальных значений столбцов можно использовать аппарат генераторов.

Генератором называется хранимый на сервере БД механизм, возвращающий уникальные значения, никогда не совпадающие со значениями, выданными данным генератором в прошлом.

Для создания генератора используется оператор CREATE GENERATOR ИмяГенератора;

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

SET GENERATOR ИмяГенератора ТО СтартовоеЗначение;

При этом СтартовоеЗначение должно быть целочисленным. Для получения уникального значения к генератору можно обратиться с помощью функции GEN_ID (ИмяГенератора, шаг);

Эта функция возвращает увеличенное на шаг предыдущее значение, выданное генератором (или увеличенное на шаг стартовое значение, если ранее обращений к генератору не было).

Значение шага должно принадлежать диапазону -231...+231 -1.

ЗАМЕЧАНИЕ.

Не рекомендуется переустанавливать стартовое значение генератора или менять шаг при разных обращениях к GEN_ID. В противном случае генератор может выдать неуникальное значение и, как следствие, будет возбуждено исключение "Дублирование первичного или уникального ключа" при попытке запоминания новой записи в ТБД. Пример.

Пусть в БД определен генератор, возвращающий уникальное значение для столбца N_RASH в таблице RASHOD:

CREATE GENERATOR RASHOD_N_RASH;

SET GENERATOR RASHOD_N_RASH TO 20;

Обращение к генератору непосредственно из оператора INSERT:

INSERT INTO RASHOD (N_RASH, DAT_RASH, KOLVO, TOVAR, POKUP)

VALUES(GEN_ID(RASHOD_N_RASH,1),"10-JAN-1997",100,"Сахар", "Лира, ТОО")

Присваивание ключевому столбцу уникального значения может быть реализовано через триггер, вызываемый перед запоминанием новой записи в БД:

CREATE TRIGGER BI_RASHOD FOR RASHOD

ACTIVE

BEFORE INSERT

AS

BEGIN

NEW.N_RASH = GEN_ID(RASHOD_N_RASH,1);

END

При этом в клиентском приложении, реализующем добавление новых записей в таблицу, столбец с уникальными значениями (в нашем случае N_RASH) в программе не заполняется и оператор INSERT имеет вид

INSERT INTO RASHOD (DAT_RASH, KOLVO, TOVAR, POKUP)

VALUES(:DAT_RASH, :KOLVO, :TOVAR, :POKUP)

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

В ряде случаев для доступа к содержимому таблиц удаленных БД в клиентских приложениях, разработанных с помощью Delphi, используют компонент TTable, который применяется для добавления, удаления и корректировки данных в этих таблицах. Здесь использование триггера может натолкнуться на неожиданное препятствие: при добавлении записи (метод Post компонента TTable) BDE отслеживает адекватность введенных значений столбцов добавляемой записи наложенным на эти столбцы ограничениям. Такой анализ осуществляется при выполнении метода Post в клиентском приложении (и, стало быть, до активизации триггера на сервере БД). При этом столбец с уникальным значением не заполнен, что с точки зрения BDE есть ошибка (поскольку данный столбец описан при создании с атрибутом NOT NULL, что обязательно для всех столбцов, входящих в первичный или просто уникальный ключ).

"Обмануть" BDE можно, присваивая столбцу N_RASH любое значение, которое затем будет заменяться триггером на значение, полученное при помощи функции GEN_ID. Однако более корректным будет в данном случае использование не триггера, а процедуры:

CREATE PROCEDURE GET_N_RASH

RETURNS (NR INTEGER)

AS

BEGIN

NR = GEN_ID(RASHOD_N_RASH,1) ;

END

При добавлении новой записи в таблицу в клиентском приложении вызов этой процедуры реализуется при помощи компонента TStoredProc, непосредственно после перевода компонента TTable в состояние dslnsert:

procedure TForm1.RashodTableAfterInsert(DataSet: TDataSet) ;

begin

StoredProc1.Close;

StoredProc1.ExecProc;

RashodTable.FieldByName('N_RASH').Value := StoredProc1.ParamByName('NR').Value;

StoredProc1.Close;

end;

Заметим, что приведенные выше действия могут быть также реализованы в обработчике события OnNewRecord компонента TTable.


Содержание раздела