Как программно присвоить уникальный идентификатор строке табличной части в 1С 8.3 при добавлении и копировании

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в среде 1С:Предприятие 8.3 программисты часто сталкиваются с классической задачей проектирования интерфейсов — организацией связи между двумя табличными частями по принципу «Главная — Подчиненная» (Master-Detail). Например, у вас есть табличная часть со списком услуг, и для каждой услуги в подчиненной табличной части необходимо указать список расходных материалов. Чтобы связать строку первой таблицы со строками второй таблицы, традиционно используется уникальный идентификатор (GUID). В этой статье мы подробно разберем, как правильно реализовать данный механизм, избежав распространенных ошибок, упомянутых на форумах разработчиков.

Мы пошагово проанализируем весь процесс: от корректного обращения к реквизитам формы до обработки копирования строк и очистки «осиротевших» данных.

Различие между ЭлементыФормы и Элементы в управляемом приложении

Начнем с синтаксической ошибки, с которой часто сталкиваются разработчики, привыкшие к обычному приложению (платформа 1С 8.2). Попытка обратиться к свойству ЭлементыФормы в управляемой форме приводит к ошибке выполнения кода. Выясним причину этого поведения.

В управляемом приложении 1С структура формы полностью изменилась. Коллекции ЭлементыФормы больше не существует. Вместо нее для доступа к визуальным элементам, расположенным на форме, используется коллекция Элементы. Рассмотрим правильный синтаксис обращения к текущим данным таблицы формы:


// Ошибка в управляемом приложении:
// ТекСтрока = ЭлементыФормы.Операции.ТекущиеДанные;

// Правильный вариант для управляемых форм:
ТекСтрока = Элементы.Операции.ТекущиеДанные;

Важно помнить, что коллекция Элементы отвечает только за визуальное представление данных на форме. Если вам необходимо работать с самими данными объекта (например, документа или справочника), обращаться следует непосредственно к основному реквизиту формы — чаще всего это Объект (например, Объект.Товары).

Как правильно сгенерировать новый УникальныйИдентификатор

Еще один важный нюанс связан с инициализацией нового идентификатора. Платформа 1С позволяет генерировать GUID с помощью специального конструктора. Однако при написании кода легко допустить опечатку, опустив ключевое слово Новый.

Проанализируем разницу в поведении платформы:

  1. Присвоение без ключевого слова Новый: Если вы напишете ТекСтрока.ИдентификаторСвязи = УникальныйИдентификатор;, платформа не выдаст синтаксическую ошибку, однако вместо нового уникального значения строке будет присвоен постоянный идентификатор самой управляемой формы. Этот идентификатор статичен на протяжении всего сеанса работы с формой. В результате все добавляемые строки получат одинаковый GUID, что сделает связь между таблицами неработоспособной.
  2. Использование конструктора Новый: Чтобы создать действительно уникальное значение, необходимо явно вызвать конструктор класса: Новый УникальныйИдентификатор.

Рассмотрим правильный пример присвоения нового идентификатора строке табличной части:


// Правильное создание и присвоение GUID
ТекСтрока.ИдентификаторСвязи = Новый УникальныйИдентификатор;

Доступ к скрытому реквизиту ТЧ (свойство «Использовать всегда»)

Часто уникальный идентификатор связи является исключительно техническим полем, которое не нужно показывать пользователю на форме. Однако у разработчиков возникает резонный вопрос: как обратиться к колонке табличной части, если соответствующий ей элемент (колонка) не выведен на форму?

В управляемом приложении 1С реализован механизм оптимизации передачи данных между сервером и клиентом. Чтобы не перегружать сетевой трафик, платформа по умолчанию не передает на клиентскую сторону значения тех реквизитов, которые не отображаются на форме в виде элементов управления. Если вы попытаетесь обратиться к скрытому реквизиту через Элементы.ИмяТаблицы.ТекущиеДанные.ИмяРеквизита, программа может вызывать ошибку или вернуть неопределенное значение.

Чтобы решить эту проблему, выполните следующие действия в конфигураторе:

  1. Откройте форму документа или справочника.
  2. Перейдите на вкладку «Реквизиты» (в правом верхнем углу редактора формы).
  3. Разверните коллекцию вашей табличной части и найдите реквизит, предназначенный для хранения уникального идентификатора.
  4. Вызовите палитру свойств этого реквизита.
  5. Найдите свойство «Использовать всегда» и установите для него флаг (значение Истина).

Установка этого флага гарантирует, что значение реквизита будет всегда передаваться на клиент, даже если колонка физически отсутствует на форме в списке видимых элементов.

Правильная обработка событий при добавлении и копировании строк

При реализации генерации GUID в событии ПриНачалеРедактирования важно правильно обрабатывать сценарии добавления новой строки и ее копирования. На форумах часто встречается ошибочное условие:


// Ошибочная логика
Если НоваяСтрока И Копирование Тогда
    // Код генерации GUID
КонецЕсли;

Такое условие никогда не выполнится корректно для генерации нового GUID. Давайте разберем почему. Когда пользователь копирует существующую строку, создается НоваяСтрока, а параметр Копирование принимает значение Истина. В новую строку копируются все данные исходной строки, включая старый уникальный идентификатор связи. Если мы оставим старый GUID, то у двух разных строк главной таблицы окажется одинаковый ключ связи, что приведет к дублированию подчиненных данных.

Правильная логика заключается в следующем: новый GUID должен генерироваться всегда, когда создается строка (будь то простое добавление новой строки или копирование существующей).

Рассмотрим по шагам реализацию обработчика события ПриНачалеРедактирования для главной таблицы формы:


&НаКлиенте
Процедура ГлавнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    // Проверяем, что строка действительно новая (создана или скопирована)
    Если НоваяСтрока Тогда
        
        ТекСтрока = Элементы.ГлавнаяТаблица.ТекущиеДанные;
        Если ТекСтрока <> Неопределено Тогда
            // Принудительно генерируем НОВЫЙ идентификатор
            // Это сбросит старый скопированный GUID и создаст новый для новой строки
            ТекСтрока.ИдентификаторСвязи = Новый УникальныйИдентификатор;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Полная реализация механизма связи «Главная — Подчиненная»

Чтобы механизм Master-Detail полноценно заработал на форме, нам необходимо реализовать еще несколько важных обработчиков событий: фильтрацию подчиненной таблицы при активизации строки главной таблицы, автоматическое заполнение ключа связи в подчиненных строках и очистку осиротевших записей.

Шаг 1. Фильтрация строк подчиненной таблицы

Когда пользователь перемещается по строкам главной таблицы, подчиненная таблица должна отображать только те строки, которые привязаны к текущей выбранной строке. Для этого мы задействуем событие ПриАктивизацииСтроки главной таблицы и механизм отбора строк. Для корректного подсчета сумм в такой подчиненной таблице подойдёт решение для расчета итогов в подвале с учетом отбора строк.

Разберем пример реализации этого обработчика:


&НаКлиенте
Процедура ГлавнаяТаблицаПриАктивизацииСтроки(Элемент)
    
    ТекДанныеГлавной = Элементы.ГлавнаяТаблица.ТекущиеДанные;
    
    // Проверяем наличие активной строки и заполненность ключа связи
    Если ТекДанныеГлавной <> Неопределено И ЗначениеЗаполнено(ТекДанныеГлавной.ИдентификаторСвязи) Тогда
        
        // Создаем фиксированную структуру для отбора строк по GUID
        ПараметрыОтбора = Новый ФиксированнаяСтруктура("ИдентификаторСвязи", ТекДанныеГлавной.ИдентификаторСвязи);
        // Применяем отбор к визуальному элементу подчиненной таблицы
        Элементы.ПодчиненнаяТаблица.ОтборСтрок = ПараметрыОтбора;
        
    Иначе
        
        // Если строка не выбрана или GUID пуст, скрываем все строки подчиненной таблицы
        Элементы.ПодчиненнаяТаблица.ОтборСтрок = Новый ФиксированнаяСтруктура("ИдентификаторСвязи", Новый УникальныйИдентификатор);
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Автозаполнение связи при добавлении подчиненной строки

Когда пользователь нажимает кнопку «Добавить» в подчиненной табличной части, новая строка должна автоматически унаследовать уникальный идентификатор из активной строки главной таблицы. В противном случае строка потеряет связь и исчезнет с экрана из-за действующего отбора строк.

Реализуем обработчик события ПриНачалеРедактирования для подчиненной таблицы:


&НаКлиенте
Процедура ПодчиненнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    Если НоваяСтрока Тогда
        
        ТекДанныеГлавной = Элементы.ГлавнаяТаблица.ТекущиеДанные;
        ТекДанныеПодчиненной = Элементы.ПодчиненнаяТаблица.ТекущиеДанные;
        
        Если ТекДанныеГлавной <> Неопределено И ТекДанныеПодчиненной <> Неопределено Тогда
            // Наследуем GUID из главной строки
            ТекДанныеПодчиненной.ИдентификаторСвязи = ТекДанныеГлавной.ИдентификаторСвязи;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 3. Удаление осиротевших строк подчиненной таблицы

Одной из частых проблем связывания таблиц на стороне клиента является накопление «мусорных» данных. Если пользователь удаляет строку из главной таблицы, связанные с ней строки в подчиненной табличной части физически остаются в документе. Они просто перестают отображаться, так как отбор больше не может на них сослаться. При записи документа эти скрытые строки будут записаны в базу данных, неоправданно увеличивая ее объем.

Чтобы предотвратить это, необходимо программно очищать подчиненные строки при удалении родительской записи. Используем для этого событие ПередУдалением главной таблицы:


&НаКлиенте
Процедура ГлавнаяТаблицаПередУдалением(Элемент, Отказ)
    
    ТекДанные = Элементы.ГлавнаяТаблица.ТекущиеДанные;
    
    Если ТекДанные <> Неопределено И ЗначениеЗаполнено(ТекДанные.ИдентификаторСвязи) Тогда
        
        ИдентификаторДляУдаления = ТекДанные.ИдентификаторСвязи;
        
        // Получаем массив строк подчиненной таблицы, которые нужно удалить
        // Поиск производим непосредственно в данных объекта на форме
        МассивСтрокНаУдаление = Новый Массив;
        Для Каждого СтрокаПодчиненной Из Объект.ПодчиненнаяТаблица Цикл
            Если СтрокаПодчиненной.ИдентификаторСвязи = ИдентификаторДляУдаления Тогда
                МассивСтрокНаУдаление.Добавить(СтрокаПодчиненной);
            КонецЕсли;
        КонецЦикла;
        
        // Удаляем связанные строки из подчиненной таблицы объекта
        Для Каждого СтрокаДляУдаления Из МассивСтрокНаУдаление Цикл
            Объект.ПодчиненнаяТаблица.Удалить(СтрокаДляУдаления);
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Благодаря предложенному комплексному подходу связь между табличными частями будет работать стабильно, корректно отрабатывать сценарии создания, копирования и удаления строк, а база данных будет защищена от появления избыточных «осиротевших» записей. Для ознакомления с готовым шаблоном реализации связывания таблиц можно использовать пример связывания главной и подчиненной таблиц на управляемых формах.

← На главную