К статье
Практический материал

Справочники и Данные · 13 мин

Как программно скопировать элемент справочника в 1С

Как программно скопировать элемент справочника в 1С: метод Скопировать(), работа с объектом и ссылкой, копирование табличных частей, типичные ошибки и примеры кода.

Копирование элемента справочника — одна из самых частых задач при разработке и доработке конфигураций 1С. Она встречается при создании шаблонов номенклатуры, клонировании настроек, массовом заполнении справочников и в обработках переноса данных. Во встроенном языке 1С для этого предусмотрен штатный метод Скопировать(), который доступен у объекта справочника.

Главная сложность заключается не в самом вызове метода, а в понимании того, что именно копируется: реквизиты, табличные части, предопределённые данные, подчинённые элементы. Часть данных переносится автоматически, а часть — например, уникальные коды, связанные регистры сведений и присоединённые файлы — требует отдельной обработки. Если этого не учесть, можно получить дубли элементов с конфликтами уникальности или потерянными данными.

Ниже разобраны основные сценарии: копирование через объект справочника, получение объекта из ссылки, копирование с модификацией реквизитов, особенности иерархических и подчинённых справочников, а также типичные ошибки и способы проверки результата.

Как работает метод Скопировать() у справочника

Метод Скопировать() вызывается у объекта типа СправочникОбъект и создаёт новый объект в памяти, в который переносятся значения всех реквизитов и строки всех табличных частей исходного элемента. Новый объект ещё не записан в базу — у него нет ссылки, пока вы не вызовете Записать(). Это удобно: между копированием и записью можно изменить любые реквизиты.

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

Базовый пример: скопировать элемент по ссылке

Самый распространённый сценарий — есть ссылка на элемент-источник, нужно создать его копию и записать. Код выглядит так:

// Источник — ссылка на существующий элемент

ИсточникСсылка = Справочники.Номенклатура.НайтиПоКоду("000000123");

Если ИсточникСсылка.Пустая() Тогда

ВызватьИсключение "Элемент-источник не найден";

КонецЕсли;

// Получаем объект и создаём копию в памяти

ИсточникОбъект = ИсточникСсылка.ПолучитьОбъект();

НовыйОбъект = ИсточникОбъект.Скопировать();

// Меняем то, что должно отличаться

НовыйОбъект.Наименование = ИсточникОбъект.Наименование + " (копия)";

НовыйОбъект.УстановитьНовыйКод();

// Записываем — только теперь элемент появляется в базе

НовыйОбъект.Записать();

Сообщить("Создан элемент: " + НовыйОбъект.Ссылка);

Обратите внимание на вызов УстановитьНовыйКод(). Если у справочника включена автонумерация и контроль уникальности кодов, копия с тем же кодом может не записаться или создать дубль кода. Явная установка нового кода снимает эту проблему. Если код не используется (длина кода равна нулю), вызов можно опустить.

Метод Скопировать() также доступен непосредственно у менеджера справочника в форме элемента — там платформа сама выполняет аналогичные действия при нажатии кнопки «Скопировать» (F9). Программный вариант нужен, когда копирование выполняется в обработке, фоновом задании или при обмене данными.

bsl
ИсточникОбъект = ИсточникСсылка.ПолучитьОбъект();
НовыйОбъект = ИсточникОбъект.Скопировать();
НовыйОбъект.УстановитьНовыйКод();
НовыйОбъект.Записать();

Копирование с изменением реквизитов и табличных частей

На практике копия редко нужна «один в один». Обычно требуется изменить наименование, владельца, родителя или отдельные строки табличной части. Всё это делается между вызовами Скопировать() и Записать(), пока объект существует только в памяти.

НовыйОбъект = ИсточникОбъект.Скопировать();

НовыйОбъект.Наименование = "Новое наименование";

НовыйОбъект.Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Архив");

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

Индекс = НовыйОбъект.ДополнительныеРеквизиты.Количество() - 1;

Пока Индекс >= 0 Цикл

Строка = НовыйОбъект.ДополнительныеРеквизиты[Индекс];

Если Строка.Свойство = НенужноеСвойство Тогда

НовыйОбъект.ДополнительныеРеквизиты.Удалить(Индекс);

КонецЕсли;

Индекс = Индекс - 1;

КонецЦикла;

НовыйОбъект.Записать();

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

Особенности иерархических и подчинённых справочников

Если справочник иерархический, копия наследует родителя источника — элемент попадёт в ту же группу. Обычно это желаемое поведение, но при копировании «шаблонных» элементов родителя часто меняют явно. Учтите: метод Скопировать() копирует только сам элемент, а не всю ветку подчинённых ему элементов или групп.

Для подчинённых справочников (например, «Единицы измерения», подчинённые «Номенклатуре») копия сохраняет ссылку на того же владельца. Если вы копируете и владельца, и подчинённые элементы, владельца у копий нужно переустановить вручную на новую ссылку — иначе они останутся привязанными к старому элементу.

// Копируем владельца

НовыйВладелец = СтарыйВладелец.ПолучитьОбъект().Скопировать();

НовыйВладелец.Записать();

// Переносим подчинённые элементы на нового владельца

Выборка = Справочники.ЕдиницыИзмерения.Выбрать(, СтарыйВладелец);

Пока Выборка.Следующий() Цикл

НоваяСтрока = Выборка.ПолучитьОбъект().Скопировать();

НоваяСтрока.Владелец = НовыйВладелец.Ссылка;

НоваяСтрока.Записать();

КонецЦикла;

Порядок действий при копировании элемента
  1. 1
    Получите ссылку на элемент-источник и проверьте, что она не пустая
  2. 2
    Вызовите ПолучитьОбъект() для перехода к редактируемому объекту
  3. 3
    Вызовите Скопировать() — получите новый объект в памяти
  4. 4
    Измените наименование, код, родителя, владельца и другие реквизиты
  5. 5
    При необходимости отредактируйте табличные части
  6. 6
    Вызовите Записать() и проверьте, что у нового объекта появилась ссылка
  7. 7
    Отдельно обработайте связанные регистры сведений и присоединённые файлы, если они нужны

Что не копируется автоматически и как это обойти

Метод Скопировать() работает только с данными самого элемента. Всё, что хранится в других объектах конфигурации, в копию не попадает. Это критично для типовых конфигураций, где значительная часть информации о номенклатуре или контрагенте лежит в регистрах сведений.

  • Регистры сведений — штрихкоды, цены, ответственные лица, дополнительные сведения. Их нужно переносить отдельным кодом: прочитать набор записей по старой ссылке, заменить измерение на новую ссылку и записать.
  • Присоединённые файлы (БСП) — картинки и документы хранятся в отдельных справочниках, привязанных к владельцу. Копируются только средствами механизмов работы с файлами.
  • Предопределённость — копия предопределённого элемента становится обычным элементом, имя предопределённых данных не наследуется.
  • История и связанные документы — копия не имеет отношения к документам, где использовался источник.

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

НаборЗаписей = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.Номенклатура.Установить(СтараяСсылка);

НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл

НоваяЗапись = РегистрыСведений.ШтрихкодыНоменклатуры.СоздатьМенеджерЗаписи();

ЗаполнитьЗначенияСвойств(НоваяЗапись, Запись);

НоваяЗапись.Номенклатура = НоваяСсылка;

НоваяЗапись.Записать();

КонецЦикла;

Альтернативные способы и когда их применять

Метод Скопировать() — не единственный путь. В зависимости от задачи удобнее могут оказаться другие подходы.

Сравнение способов копирования

Метод Скопировать()

Штатный способ: копирует реквизиты и табличные части. Подходит для большинства задач, но не трогает связанные регистры и файлы.

СоздатьЭлемент() + ЗаполнитьЗначенияСвойств()

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

Интерактивное копирование (F9)

Кнопка «Скопировать» в форме списка. Подходит для разовых операций пользователем, не требует кода, но не масштабируется.

Обработка группового изменения реквизитов

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

Вариант с ЗаполнитьЗначенияСвойств() оправдан, когда копировать нужно не всё: например, при создании «чистого» элемента по образцу без исторических настроек. При этом помните, что метод заполняет только совпадающие по именам свойства и не переносит табличные части — их придётся загружать через НовыйОбъект.ТабличнаяЧасть.Загрузить(ИсточникОбъект.ТабличнаяЧасть.Выгрузить()).

Проверка результата и типичные ошибки

После записи копии убедитесь, что элемент действительно создан и заполнен корректно. Минимальная проверка — у нового объекта появилась непустая ссылка, наименование и код отличаются от источника, табличные части содержат ожидаемое количество строк.

Контрольные точки

Как проверить результат

Ссылка нового объекта
Норма

После Записать() ссылка не пустая и отличается от источника

Тревожный признак

Ссылка пустая — запись не выполнилась, ищите исключение

Код элемента
Норма

Код уникален в пределах справочника или подчинения

Тревожный признак

Ошибка уникальности при записи или дубль кода

Табличные части
Норма

Количество строк совпадает с источником или с ожидаемым после фильтрации

Тревожный признак

Строки потеряны или задвоены

Владелец и родитель
Норма

Указаны корректно для новой логики данных

Тревожный признак

Копия осталась привязана к старому владельцу при копировании всей связки

Типичные ошибки
01
Вызов Скопировать() у ссылки вместо объекта — метод есть только у СправочникОбъект, сначала нужен ПолучитьОбъект()
02
Забытый Записать() — копия существует только в памяти и пропадает после завершения кода
03
Дубль кода при включённой уникальности — не вызван УстановитьНовыйКод(), запись падает с ошибкой
04
Удаление строк табличной части в прямом цикле — индексы смещаются, часть строк пропускается
05
Ожидание, что скопируются штрихкоды, цены и файлы — они хранятся в других объектах и требуют отдельного переноса
06
Копирование в цикле без транзакции при больших объёмах — при сбое остаются частично созданные данные

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

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

FAQ: частые вопросы о копировании элементов справочников

Можно ли скопировать элемент справочника без программирования?

Да. В форме списка справочника есть стандартная кнопка «Скопировать» (клавиша F9), которая создаёт новый элемент на основе выделенного. Это подходит для разовых операций. Программное копирование нужно для массовых обработок, обменов и автоматических сценариев.

Копируются ли табличные части при вызове Скопировать()?

Да, все табличные части элемента переносятся в копию полностью и автоматически. Если в копии нужны не все строки, лишние удаляются после копирования и до записи объекта.

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

Копия наследует код источника, а в справочнике включён контроль уникальности кодов. Перед записью вызовите у нового объекта метод УстановитьНовыйКод() — платформа назначит следующий свободный код с учётом автонумерации.

Перенесутся ли штрихкоды и цены при копировании номенклатуры?

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

Как скопировать группу справочника вместе со всеми элементами?

Метод Скопировать() копирует только один объект. Для копирования ветки нужен рекурсивный обход: скопировать группу, записать её, затем перебрать дочерние элементы и группы источника, копируя каждый и устанавливая родителем новую группу.

Чем копирование отличается от создания элемента через СоздатьЭлемент()?

СоздатьЭлемент() создаёт пустой объект, который заполняется вручную. Скопировать() создаёт объект, уже заполненный данными источника, включая табличные части. Если нужна копия с минимальными изменениями — используйте Скопировать(); если нужен принципиально другой набор данных — проще создать элемент с нуля.

Итог

Что важно запомнить

Программное копирование элемента справочника в 1С выполняется цепочкой: ПолучитьОбъект() → Скопировать() → изменение реквизитов → УстановитьНовыйКод() → Записать(). Табличные части копируются автоматически, а регистры сведений, присоединённые файлы и подчинённые справочники требуют отдельной обработки. Массовые операции тестируйте на копии базы и выполняйте в транзакции.