v8: Создание своего уникального кода для справочникаОднажды мне понадобилось создать свой уникальный код для справочника, т.к. поле Код было занято. Я столкнулся с тем, что начали появляться дубли кодов, когда пользователи одновременно записывали два элемента справочника.
Здесь метод решения этой проблемы. | | Автор статьи: Гений 1С | Редакторы: Последняя редакция №2 от 16.02.07 | История URL: http://kb.mista.ru/article.php?id=370 | |
Ключевые слова: запросы,транзакция,конкуренция
Тема горячо обсуждалась здесь: v8: v8: У меня появились дубли уникального кода, что делать?
Процедура ПередЗаписью(Отказ)
Если Не Отказ И НЕ ЭтоГруппа Тогда
//Здесь сложное условие определения, нужно ли устанавливать уникальный код.
Если ЗначениеНеЗаполнено(УникальныйКод) Или ЭтоНовый() ИЛИ ЗначениеНеЗаполнено(Ссылка.ПолучитьОбъект().УникальныйКод) Тогда
Префикс = СокрЛП(ПланыОбмена.Подразделения.ЭтотУзел().Код);
УникальныйКод=обПолучитьНовыйКод(Метаданные.Справочники.Договоры, Префикс, "УникальныйКод", Метаданные.Справочники.Договоры.Реквизиты.УникальныйКод.Тип.КвалификаторыСтроки.Длина);
КонецПроцедуры
Функция обПолучитьНовыйКод(МДОбъект, Префикс, Реквизит, Длина) Экспорт //fixin 20060728
П=обТипОбъектаПоМетаданным(МДОбъект);
Имя=МДОбъект.Имя;
Запрос=Новый Запрос("ВЫБРАТЬ
| МАКСИМУМ(Договоры.Код) КАК Зн
|ИЗ
| Справочник.Договоры КАК Договоры
|ГДЕ
| Договоры.Код ПОДОБНО &Шаблон
|
|ДЛЯ ИЗМЕНЕНИЯ");
//Очень важно использовать ДЛЯ ИЗМЕНЕНИЯ - чтобы гарантированно код был уникальным
Запрос.Текст=СтрЗаменить(Запрос.Текст, "Договоры", Имя);
Запрос.Текст=СтрЗаменить(Запрос.Текст, "Справочник", П.ИмяЕЧ);
Запрос.Текст=СтрЗаменить(Запрос.Текст, "Код", Реквизит);
Запрос.УстановитьПараметр("Шаблон", Префикс+"%"); //ПОДОБНО "АВ%", например, хотя логичнее искать цифры
Выборка=Запрос.Выполнить().Выбрать();
ДлинаПрефикса=СтрДлина(Префикс);
Выборка.Следующий();
Если Выборка.Зн<>Null Тогда
МаксКод=Число(Сред(Выборка.Зн, ДлинаПрефикса+1));
Иначе
МаксКод=0;
КонецЕсли;
МаксКод=МаксКод+1; //Увеличиваем максимальный код
Рез=Префикс+Формат(МаксКод, "ЧЦ="+Формат(Длина-ДлинаПрефикса,"ЧГ=")+"; ЧВН=; ЧГ=");
Возврат Рез;
КонецФункции
Итак, важные моменты:
Вся запись объекта происходит в одной транзакции, поэтому достаточно использовать ДЛЯ ИЗМЕНЕНИЯ в запросе к договорам, чтобы другие процессы не смогли прочитать справочник договора, пока не завершится транзакция записиНа этом я прокололся, поэтому обратите внимание: если при записи происходит ошибка блокировки и пользователь не закрыл карточку, то даже у нового объекта уникальный код уже установлен, т.к. уже прошел код по установке уникального кода. Поэтому используется такое сложное условие для определения нужно ли устанавливать уникальный код.
Код отлаживался с помощью запуска двух процессов, один из которых выдавал Предупреждение, все работает ОК.Проблема с длинной кода и ее решение
Я уже рассказывал, как средсвами 1С присвоить уникальный код с префиксом.
Конечно, ГУИД был бы надежнее, но увы, такова была постановка задачи.
Теперь мы столкнулись с следующей проблемой - длина кода 8 символов, из них первые 3 символа отводятся под префикс, остается 5 символов на код, что дает нам только 100 000 кодов. Диапазон был превышен.
Поэтому возникла проблема расширения диапазона кодов. Чтобы не менять код у уже имеющихся элементов, мы просто расширили на разряд длину кода. Но функция максимум работала неправильно.
Например, максимальный код был БББ99999, новый код равнялся 1000000. Но после этого элемент с кодом БББ99999 считался по правилам сравнения строк больше чем БББ1000000, и максимальный код опять же получался равным БББ99999.
Сначала я хотел использовать в запросе подстроку, начиная с четвертого символа, и преобразовывать ее в число. Но в 1С 80 в запросах нельзя преобразовывать строку в число, так что метод не прокатил.
Чтобы добиться нормального определения максимального кода, я исключил из запроса поиска максимального элемента элементы, длина которых меньше девяти, т.е. девятый символ равен пустой строке:
Запрос=Новый Запрос("ВЫБРАТЬ
| МАКСИМУМ(Договоры.Код) КАК Зн
|ИЗ
| Справочник.Договоры КАК Договоры
|ГДЕ
| Договоры.Код ПОДОБНО &Шаблон
| И ПОДСТРОКА(Договоры.Код, &Длина, 1) <> """"
|
|ДЛЯ ИЗМЕНЕНИЯ");
Теперь элементы с "неправильной" длиной исключались из рассмотрения. Такие вот хитрости. |