Справочники и Данные · 13 мин
Как программно скопировать элемент справочника в 1С
Как программно скопировать элемент справочника в 1С: метод Скопировать(), работа с объектом и ссылкой, копирование табличных частей, типичные ошибки и примеры кода.
Копирование элемента справочника — одна из самых частых задач при разработке и доработке конфигураций 1С. Она встречается при создании шаблонов номенклатуры, клонировании настроек, массовом заполнении справочников и в обработках переноса данных. Во встроенном языке 1С для этого предусмотрен штатный метод Скопировать(), который доступен у объекта справочника.
Главная сложность заключается не в самом вызове метода, а в понимании того, что именно копируется: реквизиты, табличные части, предопределённые данные, подчинённые элементы. Часть данных переносится автоматически, а часть — например, уникальные коды, связанные регистры сведений и присоединённые файлы — требует отдельной обработки. Если этого не учесть, можно получить дубли элементов с конфликтами уникальности или потерянными данными.
Ниже разобраны основные сценарии: копирование через объект справочника, получение объекта из ссылки, копирование с модификацией реквизитов, особенности иерархических и подчинённых справочников, а также типичные ошибки и способы проверки результата.
Как работает метод Скопировать() у справочника
Метод Скопировать() вызывается у объекта типа СправочникОбъект и создаёт новый объект в памяти, в который переносятся значения всех реквизитов и строки всех табличных частей исходного элемента. Новый объект ещё не записан в базу — у него нет ссылки, пока вы не вызовете Записать(). Это удобно: между копированием и записью можно изменить любые реквизиты.
Важно понимать, что метод не копирует служебные данные: ссылку, пометку удаления в некоторых сценариях обработки, признак предопределённого элемента и данные, хранящиеся вне самого справочника. Если элемент был помечен на удаление, копия обычно создаётся без пометки удаления, но полагаться на это стоит только после проверки в конкретной конфигурации.
Базовый пример: скопировать элемент по ссылке
Самый распространённый сценарий — есть ссылка на элемент-источник, нужно создать его копию и записать. Код выглядит так:
// Источник — ссылка на существующий элемент
ИсточникСсылка = Справочники.Номенклатура.НайтиПоКоду("000000123");
Если ИсточникСсылка.Пустая() Тогда
ВызватьИсключение "Элемент-источник не найден";
КонецЕсли;
// Получаем объект и создаём копию в памяти
ИсточникОбъект = ИсточникСсылка.ПолучитьОбъект();
НовыйОбъект = ИсточникОбъект.Скопировать();
// Меняем то, что должно отличаться
НовыйОбъект.Наименование = ИсточникОбъект.Наименование + " (копия)";
НовыйОбъект.УстановитьНовыйКод();
// Записываем — только теперь элемент появляется в базе
НовыйОбъект.Записать();
Сообщить("Создан элемент: " + НовыйОбъект.Ссылка);
Обратите внимание на вызов УстановитьНовыйКод(). Если у справочника включена автонумерация и контроль уникальности кодов, копия с тем же кодом может не записаться или создать дубль кода. Явная установка нового кода снимает эту проблему. Если код не используется (длина кода равна нулю), вызов можно опустить.
Метод Скопировать() также доступен непосредственно у менеджера справочника в форме элемента — там платформа сама выполняет аналогичные действия при нажатии кнопки «Скопировать» (F9). Программный вариант нужен, когда копирование выполняется в обработке, фоновом задании или при обмене данными.
ИсточникОбъект = ИсточникСсылка.ПолучитьОбъект();
НовыйОбъект = ИсточникОбъект.Скопировать();
НовыйОбъект.УстановитьНовыйКод();
НовыйОбъект.Записать();Копирование с изменением реквизитов и табличных частей
На практике копия редко нужна «один в один». Обычно требуется изменить наименование, владельца, родителя или отдельные строки табличной части. Всё это делается между вызовами Скопировать() и Записать(), пока объект существует только в памяти.
НовыйОбъект = ИсточникОбъект.Скопировать();
НовыйОбъект.Наименование = "Новое наименование";
НовыйОбъект.Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Архив");
// Пример: удалить из копии часть строк табличной части
Индекс = НовыйОбъект.ДополнительныеРеквизиты.Количество() - 1;
Пока Индекс >= 0 Цикл
Строка = НовыйОбъект.ДополнительныеРеквизиты[Индекс];
Если Строка.Свойство = НенужноеСвойство Тогда
НовыйОбъект.ДополнительныеРеквизиты.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
НовыйОбъект.Записать();
Удалять строки табличной части удобнее с конца коллекции, как в примере выше: при прямом переборе с начала индексы смещаются после каждого удаления, и часть строк будет пропущена. Это одна из самых частых логических ошибок при доработке копирования.
Особенности иерархических и подчинённых справочников
Если справочник иерархический, копия наследует родителя источника — элемент попадёт в ту же группу. Обычно это желаемое поведение, но при копировании «шаблонных» элементов родителя часто меняют явно. Учтите: метод Скопировать() копирует только сам элемент, а не всю ветку подчинённых ему элементов или групп.
Для подчинённых справочников (например, «Единицы измерения», подчинённые «Номенклатуре») копия сохраняет ссылку на того же владельца. Если вы копируете и владельца, и подчинённые элементы, владельца у копий нужно переустановить вручную на новую ссылку — иначе они останутся привязанными к старому элементу.
// Копируем владельца
НовыйВладелец = СтарыйВладелец.ПолучитьОбъект().Скопировать();
НовыйВладелец.Записать();
// Переносим подчинённые элементы на нового владельца
Выборка = Справочники.ЕдиницыИзмерения.Выбрать(, СтарыйВладелец);
Пока Выборка.Следующий() Цикл
НоваяСтрока = Выборка.ПолучитьОбъект().Скопировать();
НоваяСтрока.Владелец = НовыйВладелец.Ссылка;
НоваяСтрока.Записать();
КонецЦикла;
- 1Получите ссылку на элемент-источник и проверьте, что она не пустая
- 2Вызовите ПолучитьОбъект() для перехода к редактируемому объекту
- 3Вызовите Скопировать() — получите новый объект в памяти
- 4Измените наименование, код, родителя, владельца и другие реквизиты
- 5При необходимости отредактируйте табличные части
- 6Вызовите Записать() и проверьте, что у нового объекта появилась ссылка
- 7Отдельно обработайте связанные регистры сведений и присоединённые файлы, если они нужны
Что не копируется автоматически и как это обойти
Метод Скопировать() работает только с данными самого элемента. Всё, что хранится в других объектах конфигурации, в копию не попадает. Это критично для типовых конфигураций, где значительная часть информации о номенклатуре или контрагенте лежит в регистрах сведений.
- Регистры сведений — штрихкоды, цены, ответственные лица, дополнительные сведения. Их нужно переносить отдельным кодом: прочитать набор записей по старой ссылке, заменить измерение на новую ссылку и записать.
- Присоединённые файлы (БСП) — картинки и документы хранятся в отдельных справочниках, привязанных к владельцу. Копируются только средствами механизмов работы с файлами.
- Предопределённость — копия предопределённого элемента становится обычным элементом, имя предопределённых данных не наследуется.
- История и связанные документы — копия не имеет отношения к документам, где использовался источник.
Пример переноса записей регистра сведений со старой ссылки на новую:
НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(СтараяСсылка);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
НоваяЗапись = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(НоваяЗапись, Запись);
НоваяЗапись.Номенклатура = НоваяСсылка;
НоваяЗапись.Записать();
КонецЦикла;
Альтернативные способы и когда их применять
Метод Скопировать() — не единственный путь. В зависимости от задачи удобнее могут оказаться другие подходы.
Сравнение способов копирования
Штатный способ: копирует реквизиты и табличные части. Подходит для большинства задач, но не трогает связанные регистры и файлы.
Ручное заполнение нового объекта. Даёт полный контроль над тем, что переносится, но табличные части придётся копировать вручную построчно.
Кнопка «Скопировать» в форме списка. Подходит для разовых операций пользователем, не требует кода, но не масштабируется.
В типовых конфигурациях позволяет массово создавать похожие элементы без программирования, но с ограниченной гибкостью.
Вариант с ЗаполнитьЗначенияСвойств() оправдан, когда копировать нужно не всё: например, при создании «чистого» элемента по образцу без исторических настроек. При этом помните, что метод заполняет только совпадающие по именам свойства и не переносит табличные части — их придётся загружать через НовыйОбъект.ТабличнаяЧасть.Загрузить(ИсточникОбъект.ТабличнаяЧасть.Выгрузить()).
Проверка результата и типичные ошибки
После записи копии убедитесь, что элемент действительно создан и заполнен корректно. Минимальная проверка — у нового объекта появилась непустая ссылка, наименование и код отличаются от источника, табличные части содержат ожидаемое количество строк.
Как проверить результат
После Записать() ссылка не пустая и отличается от источника
Ссылка пустая — запись не выполнилась, ищите исключение
Код уникален в пределах справочника или подчинения
Ошибка уникальности при записи или дубль кода
Количество строк совпадает с источником или с ожидаемым после фильтрации
Строки потеряны или задвоены
Указаны корректно для новой логики данных
Копия осталась привязана к старому владельцу при копировании всей связки
Отдельно стоит сказать о транзакциях. Если копируется связка объектов (владелец + подчинённые элементы + записи регистров), оборачивайте всю операцию в транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Тогда при ошибке на середине база не останется в рассогласованном состоянии с «половиной» скопированных данных.
Если копирование выполняется на сервере в типовой конфигурации, проверьте, не переопределены ли обработчики ПриКопировании и ПриЗаписи в модуле объекта справочника. Типовые конфигурации часто добавляют туда свою логику — например, очистку отдельных реквизитов при копировании, и фактический результат может отличаться от ожидаемого «один в один».
FAQ: частые вопросы о копировании элементов справочников
Можно ли скопировать элемент справочника без программирования?
Да. В форме списка справочника есть стандартная кнопка «Скопировать» (клавиша F9), которая создаёт новый элемент на основе выделенного. Это подходит для разовых операций. Программное копирование нужно для массовых обработок, обменов и автоматических сценариев.
Копируются ли табличные части при вызове Скопировать()?
Да, все табличные части элемента переносятся в копию полностью и автоматически. Если в копии нужны не все строки, лишние удаляются после копирования и до записи объекта.
Почему при записи копии возникает ошибка уникальности кода?
Копия наследует код источника, а в справочнике включён контроль уникальности кодов. Перед записью вызовите у нового объекта метод УстановитьНовыйКод() — платформа назначит следующий свободный код с учётом автонумерации.
Перенесутся ли штрихкоды и цены при копировании номенклатуры?
Нет. Штрихкоды, цены и подобные данные в типовых конфигурациях хранятся в регистрах сведений, а не в самом справочнике. Их нужно переносить отдельным кодом: прочитать записи по старой ссылке, подменить ссылку на новую и записать.
Как скопировать группу справочника вместе со всеми элементами?
Метод Скопировать() копирует только один объект. Для копирования ветки нужен рекурсивный обход: скопировать группу, записать её, затем перебрать дочерние элементы и группы источника, копируя каждый и устанавливая родителем новую группу.
Чем копирование отличается от создания элемента через СоздатьЭлемент()?
СоздатьЭлемент() создаёт пустой объект, который заполняется вручную. Скопировать() создаёт объект, уже заполненный данными источника, включая табличные части. Если нужна копия с минимальными изменениями — используйте Скопировать(); если нужен принципиально другой набор данных — проще создать элемент с нуля.
Что важно запомнить
Программное копирование элемента справочника в 1С выполняется цепочкой: ПолучитьОбъект() → Скопировать() → изменение реквизитов → УстановитьНовыйКод() → Записать(). Табличные части копируются автоматически, а регистры сведений, присоединённые файлы и подчинённые справочники требуют отдельной обработки. Массовые операции тестируйте на копии базы и выполняйте в транзакции.