| 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) <> """"
                        |
                        |ДЛЯ ИЗМЕНЕНИЯ");
 Теперь элементы с "неправильной" длиной исключались из рассмотрения. Такие вот хитрости.
 |