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