Книга знаний

1С:Предприятие / v8 / Объекты конфигурации / Справочники

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) <> """"
                            |
                            |ДЛЯ ИЗМЕНЕНИЯ");


    Теперь элементы с "неправильной" длиной исключались из рассмотрения. Такие вот хитрости.

    Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
    © Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

    Яндекс.Метрика