В предыдущем шаге мы создали таблицу T_REGISTRY. Последним полем в ней было FldIntIdentity, которое, если Вы заметили, я не упомянул ни одним словом. И вот почему.
О важности уникального кода записи говорить не будем. Первичный ключ таблицы - одно из основополагающих положений реляционных баз данных. Я даже придумал следующий диалог:
Вопрос: - Может ли в таблице быть только одно поле ? Ответ: - Может - это поле уникального кода записи (первичный ключ) !
К сожалению, у VFP нет встроенного механизма присвоения значения первичного ключа для новых записей в таблице. Есть физический номер записи, который можно получить функцией recno(). Использовать его для связей между таблицами КАТЕГОРИЧЕСКИ НЕ РЕКОМЕНДУЮ !!! VFP не удаляет записи физически, а "метит" их как удаленные. Обработка удаленных записей зависит от команды SET DELETED ON | OFF. После команды PACK(физическое удаление удаленных записей и поджатие таблицы), а выполнять ее приходится, физические номера записей смещаются. Не выполнять команду PACK никогда ? ("Никогда не говори никогда"). Заниматься поиском удаленных записей и их восстановлением - было, пробовали, ничего хорошего:
Рассуждать на эту тему можно бесконечно, но что делать ? ("Хватит рассуждать - трясти надо"). Создадим свой счетчик. Вариантов может быть несколько.
Использование sys(2015) зависит от системного таймера Вашего компьютера. Не приемлемо для локальной машины, а про сеть и говорить нечего.
Можно создать системную таблицу со списком всех таблиц и хранить для каждой таблицы максимальное значение. В этом случае необходимо предусмотреть блокировку записи функцией RLOCK() для одновременной работы нескольких пользователей. В общем работает.
Но, хотелось бы, обойтись без блокировок. Их еще будет много. Добавим в базу данных D_SYSTEM папка System таблицу T_STATIONS следующей структуры:
Наименование | Тип | Ширина | Десятичные знаки |
---|---|---|---|
FldStrStationName | Char | 20 | Станция |
FldIntStationCode | Int | Код станции | |
FldIntLastKey | Int | Счетчик | |
FldIntIdentity | Int | Уникальный код |
Заполним нашу таблицу примером:
FldStrStationName | FldIntStationCode | FldIntLastKey | FldIntIdentity |
---|---|---|---|
LOCAL_WORKSTATION | 100 000 000 000 000 | 100 000 000 565 321 | 1 |
NT_SERVER_P100 | 101 000 000 000 000 | 101 000 002 324 147 | 2 |
NT_WKS_C300 | 102 000 000 000 000 | 102 000 000 022 896 | 3 |
STATION_1 | 103 000 000 000 000 | 103 000 000 001 589 | 4 |
О структуре можно спорить, но, главное, понять принцип организации счетчика. При старте нашего приложения функцией 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.