Как скопировать подчиненный справочник при копировании элемента-владельца в 1С?

Программист 1С v8.3 (Обычные формы) Сфера услуг, туризм и социальный сектор
← На главную

При интерактивном копировании элементов справочников в платформе 1С разработчики часто сталкиваются с ситуацией, когда данные подчиненных справочников или связанные с ними реквизиты (например, ссылка на основную спецификацию или рецептуру блюда) не переносятся в новый элемент либо очищаются. Рассмотрим, почему возникает такое поведение платформы и как правильно реализовать копирование подчиненных данных.

Архитектурные особенности платформы 1С при копировании

Разберем логику работы платформы при выполнении интерактивного копирования или программного вызова метода Скопировать():

  1. Автоматическое копирование только собственных данных: Платформа 1С дублирует только реквизиты самого объекта и строки его табличных частей. Элементы подчиненных справочников никогда не копируются автоматически, так как они являются самостоятельными ссылочными объектами базы данных.
  2. Требование обязательного наличия ссылки владельца: Подчиненный справочник не может существовать без заполненного реквизита Владелец. Пока новый элемент-владелец не записан в базу данных (свойство ЭтоНовый() = Истина), у него нет физической ссылки в базе. Следовательно, создать и записать подчиненный элемент до момента сохранения карточки владельца технически невозможно.
  3. Очистка реквизитов, ссылающихся на подчиненные объекты: Если у справочника-владельца (например, Справочник.Номенклатура) есть реквизит (например, ОсновнаяРецептураБлюда), указывающий на элемент подчиненного справочника (Справочник.РецептурыБлюд), типовые конфигурации намеренно очищают этот реквизит при копировании. Если этого не сделать, новая номенклатура будет ошибочно ссылаться на рецептуру, подчиненную исходному товару.

Типичные ошибки при реализации «в лоб»

Посмотрим на распространенную ошибку, которую часто допускают начинающие разработчики при попытке решить проблему через обработчик ПриЗаписи:


// Ошибочный вариант
Процедура ПриЗаписи(Отказ)
    НовРецептура = ОсновнаяРецептураБлюда.Скопировать();
    НовРецептура.Владелец = ЭтотОбъект.Ссылка;
    НовРецептура.Записать();
    
    ОсновнаяРецептураБлюда = НовРецептура.Ссылка;
КонецПроцедуры

Проанализируем, почему такой код приведет к критическим ошибкам:

  1. Дублирование данных при каждом сохранении: Если пользователь откроет уже существующий элемент, изменит любой реквизит (например, наименование или цену) и нажмет кнопку сохранения, процедура ПриЗаписи выполнится снова. В результате для товара будет повторно создана копия рецептуры, а старая станет неиспользуемым дублем.
  2. Появление «мусорных» данных при отмене: Если попытаться скопировать подчиненные элементы до записи основного объекта, а пользователь закроет форму без сохранения, в базе останутся «оторванные» подчиненные записи.

Правильный алгоритм: перенос логики в модуль объекта

Разберем надежный и универсальный способ копирования подчиненных справочников с сохранением целостности данных. Для этого используем коллекцию ДополнительныеСвойства объекта.

  1. В процедуре ПриКопировании (или ОбработкаЗаполнения) фиксируем факт того, что объект создан копированием, и сохраняем ссылку на исходный элемент в ДополнительныеСвойства.
  2. В событии ПриЗаписи проверяем наличие флага копирования. Если объект новый и ссылка на источник зафиксирована, создаем копии подчиненных элементов.
  3. Назначаем владельцем новую ссылку текущего объекта.
  4. Обновляем ссылки на основной подчиненный элемент и очищаем признак копирования, предотвращая повторное дублирование при дальнейших перезаписях.

Посмотрим на пример реализации в модуле объекта справочника-владельца (например, СправочникОбъект.Номенклатура):


Процедура ПриКопировании(ОбъектКопирования)
    // Фиксируем исходный объект во временных свойствах объекта
    ДополнительныеСвойства.Вставить("ИсточникКопирования", ОбъектКопирования.Ссылка);
КонецПроцедуры

Процедура ПриЗаписи(Отказ)
    // Проверяем, было ли выполнено копирование
    Если ДополнительныеСвойства.Свойство("ИсточникКопирования") Тогда
        Источник = ДополнительныеСвойства.ИсточникКопирования;
        
        Если ЗначениеЗаполнено(Источник) Тогда
            // Запрашиваем все подчиненные элементы исходного объекта
            Запрос = Новый Запрос;
            Запрос.Текст = 
                "ВЫБРАТЬ
                |	Рецептуры.Ссылка КАК Ссылка
                |ИЗ
                |	Справочник.РецептурыБлюд КАК Рецептуры
                |ГДЕ
                |	Рецептуры.Владелец = &Владелец";
            Запрос.УстановитьПараметр("Владелец", Источник);
            
            Выборка = Запрос.Выполнить().Выбрать();
            Пока Выборка.Следующий() Цикл
                // Создаем копию подчиненного элемента
                КопияРецептуры = Выборка.Ссылка.Скопировать();
                КопияРецептуры.Владелец = ЭтотОбъект.Ссылка;
                КопияРецептуры.Записать();
                
                // Если копируемый элемент являлся основным у источника, переназначаем его
                Если Выборка.Ссылка = Источник.ОсновнаяРецептураБлюда Тогда
                    ЭтотОбъект.ОсновнаяРецептураБлюда = КопияРецептуры.Ссылка;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
        
        // Обязательно удаляем свойство, чтобы исключить повторное срабатывание
        ДополнительныеСвойства.Удалить("ИсточникКопирования");
    КонецЕсли;
КонецПроцедуры

Альтернативный вариант: копирование на уровне формы

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

  1. Хранение ссылки на источник в реквизите формы: При открытии формы нового элемента, созданного копированием (проверяется параметр ПараметрОбъектКопирования или заполненность данных копирования), ссылка на источник помещается во временный реквизит формы ИсточникКопирования.
  2. Отображение во временной таблице: На форме табличная часть или динамический список заполняется данными источника во временную таблицу значений.
  3. Запись и привязка: В процедуре формы ПослеЗаписи (или ПослеЗаписиНаСервере) выполняется физическое создание подчиненных элементов с привязкой к полученной ссылке владельца, после чего реквизит ИсточникКопирования очищается, а элементы на форме обновляются.

Такой подход гарантирует, что в информационной базе не останется некорректных или дублирующихся ссылок, а все подчиненные спецификации и рецептуры будут корректно привязаны к новому владельцу.

← На главную