Нередко разработчикам 1С требуется сгенерировать штрихкод, уникальный номер или другой служебный реквизит на основании уникального идентификатора (GUID) ссылки документа еще в момент создания объекта. Однако при попытке прочитать свойство Ссылка у нового документа до его сохранения в базу разработчик сталкивается с тем, что ссылка пустая, а попытка заполнить реквизиты в обработчике ПриЗаписи приводит к тому, что в базе реквизит остается незаполненным. Разберем по шагам, почему так происходит и как правильно решить эту задачу средствами платформы 1С:Предприятие.
Проанализируем стандартный жизненный цикл записи объекта в платформе 1С:
Ссылка возвращает пустую ссылку.Ссылка. Но физическая запись в базу данных уже произошла! Если мы изменим значение любого реквизита в процедуре ПриЗаписи, оно изменится только в оперативной памяти текущего экземпляра объекта. При закрытии формы или завершении транзакции эти изменения будут потеряны, так как повторного автоматического сохранения в СУБД платформа не выполняет.Следовательно, для надежного сохранения значения в базе данных модификацию реквизитов необходимо выполнять исключительно в процедуре ПередЗаписью.
Платформа 1С предоставляет механизм, позволяющий заранее зарезервировать ссылку для еще не записанного объекта. Для этого менеджер соответствующего документа предоставляет метод ПолучитьСсылку(), а сам объект документа — метод УстановитьСсылкуНового().
Разберем по шагам правильный алгоритм действий в модуле объекта:
ЭтоНовый(). Метод УстановитьСсылкуНового() можно вызывать только для новых объектов, иначе платформа вызовет исключительную ситуацию.ПолучитьСсылкуНового().Документы.ЗаявкаНаРемонт.ПолучитьСсылку(...).УстановитьСсылкуНового(). Теперь платформа при физической записи сохранит объект именно с этим GUID.Посмотрим на пример реализации в модуле объекта документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЭтоНовый() Тогда
СсылкаНового = ПолучитьСсылкуНового();
Если Не ЗначениеЗаполнено(СсылкаНового) Тогда
НовыйГУИД = Новый УникальныйИдентификатор;
СсылкаНового = Документы.ЗаявкаНаРемонт.ПолучитьСсылку(НовыйГУИД);
УстановитьСсылкуНового(СсылкаНового);
КонецЕсли;
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
ШестнадцатиричныйКод = СтрЗаменить(Строка(СсылкаНового.УникальныйИдентификатор()), "-", "");
Штрихкод = ПреобразоватьИзШестнадцатиричнойСистемыСчисленияВДесятичноеЧисло(ШестнадцатиричныйКод);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Рассмотрим подробнее функции преобразования системного GUID в числовые и строковые коды различных систем счисления. Строка GUID состоит из 32 шестнадцатеричных цифр (без учета дефисов). Для компактного представления часто используют алгоритмы перевода систем счисления с основанием от 10 до 94 или 128 (включающие печатные ASCII-символы).
Приведем универсальные функции прямого и обратного преобразования систем счисления:
Функция Из_Любой_В_10(Знач Значение = "0", Нотация = 128) Экспорт
Если Нотация <= 0 Тогда
Возврат 0;
КонецЕсли;
Значение = СокрЛП(Значение);
Если Значение = "0" Тогда
Возврат 0;
КонецЕсли;
Результат = 0;
Длина = СтрДлина(Значение);
Алфавит = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~""";
Для Х = 1 По Длина Цикл
М = 1;
Для У = 1 По Длина - Х Цикл
М = М * Нотация;
КонецЦикла;
Позиция = СтрНайти(Алфавит, Сред(Значение, Х, 1));
Результат = Результат + (Позиция - 1) * М;
КонецЦикла;
Возврат Окр(Результат);
КонецФункции
Функция Из_10_В_Любую(Знач Значение = 0, Нотация = 128) Экспорт
Если Нотация <= 0 Тогда
Возврат "";
КонецЕсли;
Значение = Число(Значение);
Если Значение <= 0 Тогда
Возврат "0";
КонецЕсли;
Значение = Цел(Значение);
Результат = "";
Алфавит = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~""";
Пока Значение > 0 Цикл
Остаток = Значение % Нотация;
Результат = Сред(Алфавит, Остаток + 1, 1) + Результат;
Значение = Цел(Значение / Нотация);
КонецЦикла;
Возврат Результат;
КонецФункции
Для упаковки ссылки в компактную строку, пригодную для нанесения на этикетку, используем следующий алгоритм сжатия:
Функция УпаковатьГУИДСсылки(Ссылка) Экспорт
ГУИДСсылки = Ссылка.УникальныйИдентификатор();
ГУИДСсылкиБезДефисов = "a" + СтрЗаменить(Строка(ГУИДСсылки), "-", "");
ДесятичноеПредставление = Из_Любой_В_10(ГУИДСсылкиБезДефисов, 16);
СтоДвадцатиВосьмиричноеПредставление = Из_10_В_Любую(ДесятичноеПредставление, 94);
Возврат СтоДвадцатиВосьмиричноеПредставление;
КонецФункции
При использовании описанного подхода важно учитывать внутренние механизмы платформы 1С и СУБД:
Число поддерживает максимальную точность в 38 десятичных знаков. Полный 128-битный GUID при переводе в десятичную систему может содержать до 39 знаков, что при прямом преобразовании вызовет переполнение или потерю точности. Если требуется числовой код, рекомендуется сохранять его как строку (Строка) либо использовать хеширование части идентификатора.Новый УникальныйИдентификатор() создает псевдослучайное значение. При интенсивной записи документов установка случайных ссылок может вызывать сильную фрагментацию кластерных индексов в MS SQL Server или PostgreSQL.ПередЗаписью рекомендуется выносить в общие модули через механизм ПодпискиНаСобытия с источником ДокументОбъект.<ИмяДокумента>.