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