Шаг 10 - Уникальный код записи в таблицах VFP

В предыдущем шаге мы создали таблицу T_REGISTRY. Последним полем в ней было FldIntIdentity, которое, если Вы заметили, я не упомянул ни одним словом. И вот почему.

О важности уникального кода записи говорить не будем. Первичный ключ таблицы - одно из основополагающих положений реляционных баз данных. Я даже придумал следующий диалог:

Вопрос:
- Может ли в таблице быть только одно поле ?
Ответ:
- Может - это поле уникального кода записи (первичный ключ) !

К сожалению, у VFP нет встроенного механизма присвоения значения первичного ключа для новых записей в таблице. Есть физический номер записи, который можно получить функцией recno(). Использовать его для связей между таблицами КАТЕГОРИЧЕСКИ НЕ РЕКОМЕНДУЮ !!! VFP не удаляет записи физически, а "метит" их как удаленные. Обработка удаленных записей зависит от команды SET DELETED ON | OFF. После команды PACK(физическое удаление удаленных записей и поджатие таблицы), а выполнять ее приходится, физические номера записей смещаются. Не выполнять команду PACK никогда ? ("Никогда не говори никогда"). Заниматься поиском удаленных записей и их восстановлением - было, пробовали, ничего хорошего:

Рассуждать на эту тему можно бесконечно, но что делать ? ("Хватит рассуждать - трясти надо"). Создадим свой счетчик. Вариантов может быть несколько.

Использование sys(2015) зависит от системного таймера Вашего компьютера. Не приемлемо для локальной машины, а про сеть и говорить нечего.

Можно создать системную таблицу со списком всех таблиц и хранить для каждой таблицы максимальное значение. В этом случае необходимо предусмотреть блокировку записи функцией RLOCK() для одновременной работы нескольких пользователей. В общем работает.

Но, хотелось бы, обойтись без блокировок. Их еще будет много. Добавим в базу данных D_SYSTEM папка System таблицу T_STATIONS следующей структуры:

T_STATIONS
НаименованиеТипШиринаДесятичные знаки
FldStrStationNameChar20Станция
FldIntStationCodeInt Код станции
FldIntLastKeyInt Счетчик
FldIntIdentityInt Уникальный код

Заполним нашу таблицу примером:

FldStrStationNameFldIntStationCodeFldIntLastKeyFldIntIdentity
LOCAL_WORKSTATION100 000 000 000 000100 000 000 565 3211
NT_SERVER_P100101 000 000 000 000101 000 002 324 1472
NT_WKS_C300102 000 000 000 000102 000 000 022 8963
STATION_1103 000 000 000 000103 000 000 001 5894

О структуре можно спорить, но, главное, понять принцип организации счетчика. При старте нашего приложения функцией sys(0) мы получаем сетевое имя машины. Функция sys(0) возвращает сетевое имя машины и имя пользователя, разделенные символом #:

?sys(0)
MachineName # UserName

Для поля FldStrStationName необходимо создать индекс TAG_NAME типа Primary. А теперь пишем функцию для получения нового значения счетчика GetNewCodeUniq():

*
* function GetNewCodeUniq
    local intLocReturn, strLocSysZero, strLocMachine
    intLocReturn = 0
    strLocSysZero = sys(0)
    strLocMachine = padr(alltrim(left(strLocSysZero,at("#",strLocSysZero)-1)),20)
* для отдельно стоящей машины
    if empty(strLocMachine)
       strLocMachine = padr("LOCAL_WORKSTATION",20)
    endif
    if (OpenTable(".\System\T_Stations.DBF", "AliasSystemStations") > 0)
      if seek(strLocMachine,"AliasSystemStation","TAG_NAME")
        intLocReturn = AliasSystemStation.FldIntLastKey + 1
        replace FldIntLastKey with intLocReturn in AliasSystemStation
      endif
    endif
return intLocReturn
* 

Обработку возникающих ошибок каждый должен придумать самостоятельно. Итак, за счет префикса станции, мы обеспечили уникальность счетчика для каждой машины в сети без применения блокировок записей.

Пример использования:

*
local intLocNewCodeUniq
intLocNewCodeUniq = GetNewCodeUniq()
*
insert into MyTable (FldStrName,FldIntIdentity) values ("Новое наименование",intLocNewCodeUniq)
*

Вот теперь мы можем, и должны создавать во всех наших таблицах для поля FldIntIdentity индекс TAG_CODE типа Primary. Если в таблице необходимо обеспечить несколько уникальных индексов, то только один из них может быть Primary. В этом случае другие такие индексы нужно создавать типа Candidate. Разница только в названии типа. Обычные индексы, которые могут содержать повторяющиеся значения, создаются типа Regular. Тип индекса Unique включен для обратной совместимости с предыдущими версиями FoxPro.


Предыдущий Шаг | Оглавление
Автор Сергей Платонов - 6.02.2000