При разработке в среде «1С:Предприятие 8» перед разработчиками нередко возникает задача связать строки одной табличной части со строками другой (например, связать основные товары со спецификациями, сериями или подарочными наборами). Также уникальные маркеры строк требуются при интеграции с внешними информационными системами. Самый надежный способ реализовать такую связь — использовать полноценный уникальный идентификатор (UUID/GUID) для каждой строки.
Однако на практике разработчики часто сталкиваются с неприятной проблемой: после создания строки реквизит с типом УникальныйИдентификатор упорно остается пустым, принимая вид нулевого значения: 00000000-0000-0000-0000-000000000000. При этом код присвоения кажется абсолютно верным и логичным. В рамках этой статьи мы подробно разберем, почему возникает эта ошибка, детально проанализируем внутренние механизмы платформы управляемых форм и рассмотрим правильные варианты решения задачи.
Давайте проанализируем, почему стандартный код присвоения значения в обработчике формы не срабатывает, если ваш реквизит называется «Ключ». В платформе «1С:Предприятие 8» существует ряд зарезервированных системных имен, которые используются внутренними механизмами ядра. К таким именам относятся: Ключ, Индекс, Статус, Объект, Дата, Элемент.
Слово «Ключ» активно эксплуатируется платформой в контексте управляемых форм и объектной модели данных:
Параметры.Ключ отвечает за передачу ссылки на открываемый объект базы данных.КлючУникальности используется для контроля открытия уникальных окон.КлючЗаписи определяет уникальный набор измерений.Когда вы создаете в табличной части пользовательский реквизит с именем Ключ, визуально в конфигураторе это не вызывает ошибок. Однако в процессе работы в режиме «1С:Предприятие» при попытке обратиться к свойству через ТекущиеДанные.Ключ возникает конфликт. Платформа путает ваш прикладной реквизит с внутренними идентификаторами строк или свойствами формы. В результате трансляции данных между клиентом и сервером значение сбрасывается обратно в пустое системное значение (нули).
Решение проблемы чрезвычайно простое: необходимо полностью отказаться от использования имени «Ключ» для пользовательских реквизитов. Переименуйте реквизит табличной части в уникальное прикладное имя, например: КлючСтр, ИдентификаторСвязи, ИдСтрокиТЧ или УникальныйИдентификаторСтроки. Это мгновенно устранит конфликт имен на уровне платформы.
В процессе обсуждения подобных проблем среди разработчиков часто возникает заблуждение, будто свойство таблицы формы ТекущиеДанные предназначено исключительно для чтения, а для записи обязательно нужно переходить на сервер и работать напрямую с объектом. Давайте разберем этот момент подробнее.
Свойство ТекущиеДанные элемента управляемой формы «Таблица» доступно только на клиенте. Оно возвращает объект типа ДанныеФормыЭлементКоллекции. Этот объект абсолютно доступен для записи на клиенте. Любые интерактивные или программные изменения его колонок (например, Элементы.ТЧТовары.ТекущиеДанные.Количество = 5;) немедленно отображаются на экране пользователя и автоматически синхронизируются с данными формы на сервере при ближайшем вызове. Переходить на сервер только ради изменения реквизитов текущей строки — избыточная операция, которая создает лишнюю нагрузку на сетевой трафик.
Однако если вам действительно необходимо модифицировать строку табличной части внутри серверной процедуры (где свойство ТекущиеДанные недоступно), правильный алгоритм работы будет выглядеть следующим образом:
Элементы.ТЧТовары.ТекущаяСтрока.НайтиПоИдентификатору().Посмотрим на пример реализации такого серверного изменения:
&НаКлиенте
Процедура ИзменитьРеквизитНаСервере()
// Получаем числовой идентификатор строки на клиенте
ИдентификаторСтроки = Элементы.ТЧТовары.ТекущаяСтрока;
Если ИдентификаторСтроки <> Неопределено Тогда
ЗаполнитьРеквизитНаСервере(ИдентификаторСтроки);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьРеквизитНаСервере(ИдентификаторСтроки)
// Находим строку в коллекции ДанныеФормыКоллекция по идентификатору
ТекущаяСтрокаОбъекта = Объект.ТЧТовары.НайтиПоИдентификатору(ИдентификаторСтроки);
Если ТекущаяСтрокаОбъекта <> Неопределено Тогда
ТекущаяСтрокаОбъекта.КлючСтр = Новый УникальныйИдентификатор;
КонецЕсли;
КонецПроцедуры
Для построения грамотной архитектуры решения важно четко разграничивать два понятия:
1. Временный идентификатор строки таблицы формы. При выводе табличной части на управляемую форму платформа автоматически генерирует для каждой строки внутренний числовой идентификатор. Его можно получить с помощью метода ПолучитьИдентификатор() или через свойство ТекущаяСтрока. Этот идентификатор существует исключительно в оперативной памяти клиента в рамках текущего сеанса работы формы. Как только форма закрывается, или как только данные табличной части перезаполняются (например, при повторном считывании из базы данных), эти идентификаторы генерируются заново и старые значения безвозвратно теряются. Они не сохраняются в базу данных.
2. Хранимый UUID (УникальныйИдентификатор). Это полноценный реквизит вашей табличной части, созданный в метаданных конфигуратора. Значение такого реквизита генерируется программно с помощью конструктора Новый УникальныйИдентификатор. Этот GUID сохраняется непосредственно в таблицы базы данных при записи документа или справочника. Он остается неизменным на протяжении всей «жизни» документа, что позволяет использовать его для долгосрочной связи строк разных табличных частей или для интеграции со сторонними сервисами.
Для того чтобы автоматизировать процесс генерации уникального идентификатора при интерактивном добавлении строки пользователем (через кнопку «Добавить», клавишу Insert или копированием существующей строки), лучше всего использовать специализированное событие таблицы формы — ПриНачалеРедактирования.
Рассмотрим по шагам, как настроить и написать этот обработчик. Этот подход гарантирует, что каждый раз при создании новой строки колонка КлючСтр будет автоматически заполняться валидным уникальным значением формата RFC 4122 без лишних обращений к серверу.
&НаКлиенте
Процедура ТЧТоварыПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
// Проверяем, что строка действительно вновь создаваемая, а не редактируемая старая
Если НоваяСтрока Тогда
// Быстрая генерация GUID непосредственно на клиенте
НовыйGUID = Новый УникальныйИдентификатор;
// Корректное заполнение реквизита через ТекущиеДанные элемента таблицы
Элемент.ТекущиеДанные.КлючСтр = НовыйGUID;
КонецЕсли;
КонецПроцедуры
Использование параметра Элемент.ТекущиеДанные внутри предопределенных событий элемента управления является стандартом разработки под управляемое приложение. Конструктор Новый УникальныйИдентификатор без параметров работает чрезвычайно быстро на стороне клиента, не вызывая сетевых задержек.
Если добавление строк в табличную часть происходит программно в серверном модуле (например, при заполнении ТЧ по какому-либо алгоритму или при импорте данных из файла Excel), то обращаться к элементам формы нельзя. В таком случае мы работаем напрямую с объектом метаданных.
Рассмотрим пример программного заполнения табличной части на сервере с генерацией уникальных идентификаторов:
&НаСервере
Процедура ЗаполнитьТабличнуюЧастьПрограммноНаСервере()
// Очищаем существующие строки перед заполнением
Объект.ТЧТовары.Очистить();
// Эмулируем цикл создания новых строк данных
Для Счетчик = 1 По 10 Цикл
// Добавляем новую строку в коллекцию объекта
НоваяСтрока = Объект.ТЧТовары.Добавить();
// Заполняем стандартные прикладные реквизиты
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00000001");
НоваяСтрока.Количество = 1;
// Генерируем и присваиваем хранимый UUID в переименованную колонку
НоваяСтрока.КлючСтр = Новый УникальныйИдентификатор;
КонецЦикла;
КонецПроцедуры
Если мы заглянем под капот крупных тиражных решений от фирмы «1С» (таких как 1С:ERP Управление предприятием, 1С:Комплексная автоматизация или 1С:Управление торговлей), мы увидим, что механизмы уникальной идентификации строк используются там повсеместно. Например, они необходимы для сопоставления номенклатуры с ее сериями, характеристиками, упаковочными листами и штрихкодами.
В типовых конфигурациях разработчики применяют следующие подходы:
КлючСвязи (обычно имеет тип Число для экономии места в базе данных, если связь нужна локально в рамках одного документа) или ИдентификаторСтроки (тип УникальныйИдентификатор для сквозной глобальной интеграции).ОбщегоНазначенияУТ.ДобавитьИндентификаторСтрокВТаблицу() берут на себя рутинную работу по обходу коллекций и массовой генерации GUID.Для успешной и стабильной работы с уникальными идентификаторами в строках табличных частей 1С достаточно придерживаться трех золотых правил:
КлючСтр или ИдентификаторСтроки.ПолучитьИдентификатор(), если связь нужна только на время работы открытой формы, и полноценный реквизит типа УникальныйИдентификатор, если связь должна быть записана в базу данных.