При разработке сложных модулей на платформе 1С:Предприятие 8 часто возникает задача клонирования целых веток иерархических справочников. Типичная ситуация: пользователь создал сложную структуру из групп и элементов, каждый из которых содержит важные данные в табличных частях (ТЧ), и теперь ему необходимо продублировать всю эту ветку для новой задачи. Стандартная кнопка «Скопировать» в интерфейсе решает задачу лишь частично — она создает копию только текущего объекта, игнорируя его подчиненную иерархию.
В этой статье мы подробно разберем, как реализовать механизм «глубокого копирования», научимся правильно работать с табличными частями и поймем, почему терминология «программного создания ТЧ» часто вводит новичков в заблуждение.
Для начала проанализируем важный теоретический аспект, который часто вызывает споры на форумах. В среде 1С невозможно программное создание табличной части в режиме «Предприятие». Структура табличных частей (их состав, имена колонок, типы данных) жестко задается в Конфигураторе. Когда мы говорим о «создании ТЧ программно», мы на самом деле имеем в виду заполнение данными уже существующей структуры, предусмотренной метаданными справочника.
Если в вашем справочнике предусмотрена табличная часть, она будет присутствовать у каждого созданного элемента или группы (если это разрешено настройками иерархии). Наша задача — не «создать» таблицу, а программно добавить в нее строки и перенести значения из исходного объекта.
Рассмотрим стандартный механизм платформы. Метод Скопировать(), доступный для ссылок справочников, создает новый объект того же типа и копирует в него все реквизиты и данные табличных частей текущего элемента.
// Пример простого копирования одного элемента
ИсходнаяСсылка = Справочники.МойСправочник.НайтиПоНаименованию("Элемент 1");
НовыйОбъект = ИсходнаяСсылка.Скопировать();
НовыйОбъект.Наименование = ИсходнаяСсылка.Наименование + " (копия)";
НовыйОбъект.Записать();
Проанализируем ситуацию: если «Элемент 1» является группой, внутри которой находятся другие элементы, метод Скопировать() создаст новую группу, но она будет пустой. Подчиненные элементы не перенесутся автоматически, так как в базе данных они являются самостоятельными записями, связанными с родителем через реквизит Родитель.
Для того чтобы скопировать всю ветку «сверху вниз», нам необходимо использовать рекурсию. Разберем этот процесс по шагам:
Родитель совпадает с исходным узлом.Посмотрим на пример реализации такой функции:
Процедура СкопироватьВеткуСправочника(ИсходныйРодитель, НовыйРодитель = Неопределено)
// 1. Получаем выборку всех детей текущего родителя
Выборка = Справочники.НашСправочник.Выбрать(ИсходныйРодитель);
Пока Выборка.Следующий() Цикл
// 2. Копируем текущий объект (группу или элемент)
НовыйОбъект = Выборка.Ссылка.Скопировать();
// 3. Устанавливаем нового родителя
НовыйОбъект.Родитель = НовыйРодитель;
// 4. Записываем объект для получения ссылки
НовыйОбъект.Записать();
// 5. Если это группа, уходим в рекурсию для копирования вложенных элементов
Если Выборка.ЭтоГруппа Тогда
СкопироватьВеткуСправочника(Выборка.Ссылка, НовыйОбъект.Ссылка);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Как мы выяснили, метод Скопировать() автоматически переносит данные ТЧ. Однако, если вы создаете новый объект методом СоздатьЭлемент() или СоздатьГруппу(), вам придется переносить данные табличных частей вручную. Рассмотрим, как сделать это максимально производительно.
Вместо перебора строк в цикле и использования метода Добавить(), проанализируем методы Выгрузить() и Загрузить(). Это наиболее быстрый способ копирования данных между идентичными структурами.
// Быстрое копирование ТЧ между объектами
ТаблицаДанных = ИсходныйОбъект.СоставПроекта.Выгрузить();
НовыйОбъект.СоставПроекта.Загрузить(ТаблицаДанных);
Важный момент: если в табличной части содержатся ссылки на элементы, которые мы также копируем в рамках данной операции, то после «Загрузить» в новой ТЧ останутся ссылки на старые объекты. В таких случаях требуется дополнительный обход строк для замены старых ссылок на новые («зеркальное» копирование).
При работе с большими иерархиями (сотни и тысячи элементов) запись каждого объекта по отдельности может занять значительное время. Выясним, как ускорить этот процесс.
Во-первых, используем Транзакции. Оборачивая весь цикл копирования в транзакцию, мы заставляем систему записывать данные в базу одним блоком, что в разы ускоряет работу и гарантирует целостность: если произойдет ошибка, вся недокопированная ветка будет удалена автоматически.
Во-вторых, используем свойство ОбменДанными.Загрузка. Установка этого флага в значение Истина отключает платформенные и прикладные проверки в модуле объекта (например, проверку заполнения реквизитов или сложные расчеты при записи), что критически важно для производительности.
НачатьТранзакцию();
Попытка
// Код рекурсивного копирования
НовыйОбъект.ОбменДанными.Загрузка = Истина;
НовыйОбъект.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при копировании: " + ОписаниеОшибки());
КонецПопытки;
Проанализировав задачу, мы пришли к выводу, что программное управление иерархией в 1С требует понимания работы ссылочных типов и механизмов рекурсии. Помните следующие правила:
Скопировать() — ваш лучший друг для копирования одного уровня, но для иерархии его нужно встраивать в рекурсивную функцию.Выгрузить() и Загрузить() — это профессиональный стандарт работы с коллекциями строк.Такой подход позволит вам создавать надежные и быстрые инструменты для пользователей, автоматизируя рутинные операции по заполнению сложных справочников.