Работа с автоинкрементальным типом поля (Auto-increment, поле
с автоприращением)
В приложениях Delphi, при использовании таблиц, содержащих
автоинкрементальные поля или поля, автоматически увеличивающие
каким-либо способом, неизвестным приложению, свое значение, могут
наблюдаться проблемы. Таблицы Paradox, InterBase, Sybase и Informix
имеют средства автоматической вставки и обновления значений полей,
без вмешательства сервисов и конечных приложений. Тем не менее, не
каждая операция с таблицой поддерживается таким механизмом. Данный
документ призван продемонстрировать основные методы работы с такими
типами полей в таблицах Paradox 5.0, Informix 5.x, MS/Sybase SQL
Server 4.x, InterBase 4.0 и Local InterBase.
У каждого типа таблицы за кулисами работает собственный механизм.
Таблицы Paradox поддерживают автоинкрементальный (Autoincrement) тип
поля. Когда к таким таблицам добавляются новые записи, Borland
Database Engine определяет максимальное текущее значение в данной
колонке, прибавляет единицу, и обновляет новую строку с новым
значением.
Для таблиц Informix данное поведение предусматривается
специфическим типом Informix-поля, названного Serial. Колонки Serial
отличаются от автоприращиваемых (Autoincrement) полей Paradox тем,
что в таблицах Informix значения этого типа полей могут быть
изменены, тогда как в таблицах Paradox они предназначены только для
чтения.
Таблицы InterBase и MS/Sybase SQL Server не имеют поддерживающего
данную характеристику специального типа поля, но для выполнения той
же задачи можно воспользоваться триггерами. Триггеры являются
специализированными процедурами, которые находятся на сервере баз
данных и автоматически выполняются в ответ на какое-либо событие,
например, добавление в таблицу, обновление и удаление. Использование
таблиц со связанными триггерами может быть особенно проблематичным,
поскольку триггеры способны делать намного больше функций, чем
просто увеличивать значения приращиваемой колонки.
Три функциональные области, которые могут влиять на данный тип
поля в случае простой вставки, batchmoves и привязки (Linking)
таблицы.
Обработка Update и/или Append BatchMoves
Таблицы Paradox
Поскольку автоинкрементальный тип поля является типом только для
чтения, то попытка вызвать операцию batchmove с данной колонкой в
целевой таблице может привести к ошибке. Для того, чтобы обойти это,
свойство компонента TBatchMove Mappings должно быть установлено так,
чтобы поля исходной таблицы соответствовали полям целевой таблицы,
за исключением ее автоинкрементальных полей.
Таблицы Informix
Групповое перемещение строк в таблицу Informix с колонками,
имеющими тип Serial, ошибки не вызовет. Тем не менее, должны вас
предупредить о возможных проблемах, поскольку Serial-колонки имеют
возможность обновления и часто используются в качестве первичного
ключа.
Таблицы InterBase Таблицы MS/Sybase SQL Server
Триггеры в таблицах InterBase и SQL Server могут отследить любые
неверные изменения, сделанные в таблице, но это всецело зависит от
установок самого триггера. Здесь также вас необходимо предупредить о
возможных проблемах, поскольку обновляемые триггером колонки могут
быть использованы в качестве первичного ключа.
Привязки таблиц посредством MasterSource &
MasterFields
Таблицы Paradox Таблицы Informix
Если свойства MasterFields и MasterSource используются для
привязки таблиц с отношениями мастер-деталь и одно из полей в
"деталь"-таблице является автоинкрементальным или Serial-полем, то
соответствующее поле в "мастер"-таблице должно иметь тип Long
Integer или быть Serial-полем. Если "мастер"-таблица не является
таблицей Paradox, то ключевое поле "мастер"-таблицы может быть полем
любого целого типа, которого она поддерживает.
Таблицы InterBase Таблицы MS/Sybase SQL Server
Привязка с использованием данного типа таблиц не вызывает
проблем, если пользоваться полями, изменяемые триггером.
Единственное требование заключается в сопоставлении необходимых
типов колонок обоих таблиц.
Простая вставка/обновление (Inserts/Updates)
Таблицы Paradox
Поскольку автоинкрементальные поля Paradox имеют аттрибут только
для чтения, они обычно не предназначены для обновления и вставки
новых записей. Следовательно, свойство Required для
field-компонентов, базирующихся на автоинкрементальных полях, должны
всегда быть установлены в False. Это может быть выполнено из Delphi
с помощью Fields Editor определением field-компонентов в режиме
разработки) двойной щелчок на компоненте TQuery или TTable), или во
время работы программы с помощью следующего кода:
Table1.Fields[0].Required := False;
|
или
Table1.FieldByName('Fieldname').Required := False;
|
Таблицы Informix
Хотя Serial-поля Informix и являются обновляемыми, но если у них
должна быть использована характеристика автоприращения, то свойство
Required для field-компонентов, базирующихся на таком поле, должно
быть установлена в False. Делайте все также, как это было описано
для таблиц Paradox.
Таблицы InterBase Таблицы MS/Sybase SQL Server
Обработка вставки этих изменяемых триггером типов таблиц требует
предпринять некоторое количество шагов. Дополнительные шаги особенно
необходимы в том случае, если вставка выполняется посредством
стандартных элементов управления для работы с базами данных, типа
DBEdits или DBMemos.
Вставка строк в изменяемые триггерами InterBase- и SQL Server
таблицы может с достаточной долей вероятности вызвать сообщение об
ошибке 'Record/Key Deleted'. Это сообщение об ощибки появляется
несмотря на то, что таблица правильно обновляется на сервере. Это
происходит в случае, если:
1. Триггер обновляет первичный ключ. Ошибка может возникнуть не
только при использовании триггера, но триггер является наиболее
вероятной причиной ошибки.
2a. Другие колонки таблицы имеют связанные значения по умолчанию.
Это выполняется ПО УМОЛЧАНИЕ в случае создания таблицы InterBase или
хранимой на сервере SQL Server процедурой sp_bindefault.
или
2b. При вставке новой строки обновляются поля, имеющие тип Blob.
или
2b. В таблице InterBase определены калькулируемые поля.
Основополагающая причина этих ошибок кроется в том, что когда
запись (или идентификационный ключ) изменяется на сервере, BDE
больше не имеет способов идентифицировать запись для ее повторного
поиска. То есть запись больше не появляется, как это было бы, если
бы ее "запостили", следовательно, BDE будет думать, что запись
удалена (или изменен ключ).
Во-первых, field-компоненты изменяемых триггером полей должны
иметь свойство Required, установленное в False. Делайте все также,
как это было описано для таблиц Paradox.
Во-вторых, чтобы избежать случайных ошибок, установите порядок
таблицы по индексу, не использующему поля, обновляемые триггером.
Это также не позволит вновь введенной записи исчезать сразу после ее
вставки.
Наконец, если условие 1, приведенное выше, невозможно, но
возможно наступление событий 2a, 2b или 2c, то необходимо создать
обработчик события AfterPost компонента TTable как показано
ниже:
procedure TForm1.Table1AfterPost(DataSet: TDataset);
begin
Table1.Refresh;
end;
|
Метод Refresh вновь перечитывает значения, измененные сервером.
Если выполнение условий 2a, 2b или 2c невозможно, то таблица
могла бы быть обновлена без элементов управления Delphi для работы с
базами данных. Это может быть выполенено с помощью компонента
TQuery, ссылающегося на ту же самую таблицу. После того, как будет
послан запрос на обновление, любые TTable-компоненты, использующие
ту же самую таблицу, должны быть обновлены (Refreshed). |