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

Разработка и Конфигурация · 12 мин

Как получить ссылку еще не записанного объекта в 1С

Как получить ссылку на еще не записанный объект в 1С: метод ПолучитьСсылку(), УстановитьСсылкуНового, работа с уникальным идентификатором и типичные ошибки.

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

Ключевой момент: ссылка в 1С — это по сути обертка над уникальным идентификатором (GUID) плюс тип объекта. Пока объект не записан, его идентификатор уже может существовать и использоваться в других объектах, но самой записи в таблице базы данных еще нет. Это создает риск появления «битых ссылок», если объект со ссылкой так и не будет записан.

Ниже разобраны рабочие способы получения ссылки до записи, примеры кода для справочников и документов, проверка результата, ограничения механизма и типичные ошибки, которые приводят к потере данных или битым ссылкам.

Зачем нужна ссылка до записи объекта

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

Вторая частая задача — обмен данными. При загрузке объектов из внешней системы или другой базы 1С ссылка часто приходит вместе с данными (в виде GUID). Чтобы объект в приемнике получил именно эту ссылку, используется связка ПолучитьСсылку(Новый UUID) у менеджера объекта и УстановитьСсылкуНового() у создаваемого объекта.

Третий сценарий — заполнение табличной части документа ссылками на номенклатуру, которая создается в том же алгоритме. Без предварительной ссылки пришлось бы сначала записывать все элементы справочника, что усложняет откат при ошибке.

Способ 1: ПолучитьСсылку() у нового объекта

Самый простой путь — создать объект через Справочники.ИмяСправочника.СоздатьЭлемент() (или СоздатьДокумент() для документов) и сразу вызвать у него метод ПолучитьСсылку(). Метод возвращает ссылку, которую объект получит при записи.

bsl
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "ООО Ромашка";

СсылкаКонтрагента = НовыйКонтрагент.ПолучитьСсылку();

Договор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
Договор.Владелец = СсылкаКонтрагента;
Договор.Наименование = "Основной договор";

НовыйКонтрагент.Записать();
Договор.Записать();

Механизм работает так: при создании объекта платформа генерирует для него уникальный идентификатор. Метод ПолучитьСсылку() строит объект ссылки на основе этого идентификатора и типа метаданных. До записи такая ссылка «висячая»: СсылкаКонтрагента.ПолучитьОбъект() вернет Неопределено, а запрос по ней не найдет строки в таблице.

Важно понимать, что ПолучитьСсылку() у объекта и одноименный метод у менеджера (Справочники.Контрагенты.ПолучитьСсылку()) — разные методы. У объекта он не принимает параметров и возвращает ссылку этого конкретного объекта. У менеджера он принимает уникальный идентификатор и строит ссылку из него, даже если объекта с таким GUID в базе нет.

Способ 2: ссылка из заранее известного GUID

Когда идентификатор известен заранее — например, пришел из файла обмена или сформирован в вашем коде, — ссылку строят через менеджер объекта:

bsl
Идентификатор = Новый УникальныйИдентификатор("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(Идентификатор);

// Проверяем, не занят ли уже этот GUID
Если Не НоваяСсылка.ПолучитьОбъект() = Неопределено Тогда
    ВызватьИсключение "Объект с таким идентификатором уже существует";
КонецЕсли;

НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
НовыйЭлемент.УстановитьСсылкуНового(НоваяСсылка);
НовыйЭлемент.Наименование = "Новая позиция";
НовыйЭлемент.Записать();

Метод УстановитьСсылкуНового() назначает объекту конкретную ссылку. Вызвать его нужно до записи и до обращения к ПолучитьСсылку(), иначе объект уже будет связан со сгенерированным идентификатором. После записи объект окажется в базе именно с указанным GUID.

Если вызвать ПолучитьСсылку() у менеджера без параметра, платформа сама сгенерирует новый уникальный идентификатор и вернет ссылку на его основе. Это удобно, когда нужна «заготовка» ссылки, которую вы потом навяжете объекту через УстановитьСсылкуНового().

Работа с документами и планами обмена

Для документов логика полностью аналогична: Документы.РеализацияТоваровУслуг.СоздатьДокумент(), затем ПолучитьСсылку() или УстановитьСсылкуНового(). Отличие в том, что у документа ссылка становится «полноценной» только после записи с любым режимом — проведение здесь ни при чем, ссылка не зависит от движений.

Для планов видов характеристик, планов счетов и планов видов расчета используются те же методы менеджеров: ПланыВидовХарактеристик.Имя.ПолучитьСсылку(Идентификатор) и СоздатьЭлемент() с последующим УстановитьСсылкуНового(). У бизнес-процессов и задач механизм тоже присутствует, хотя на практике применяется реже.

Сравнение подходов

ПолучитьСсылку() у объекта

Подходит, когда идентификатор не важен и нужна просто ссылка будущего объекта. Минимум кода, GUID генерируется платформой.

Менеджер.ПолучитьСсылку(GUID) + УстановитьСсылкуНового

Нужен при обмене и синхронизации, когда ссылка должна совпасть с источником. Требует контроля уникальности GUID.

Записать() и взять Ссылка

Самый безопасный вариант, если нет требования записывать объекты одной транзакцией. Не подходит для связанных объектов без дополнительного кода.

Проверка результата и контроль битых ссылок

После записи убедитесь, что объект действительно появился в базе с ожидаемой ссылкой. Простейшая проверка — сравнить НовыйЭлемент.Ссылка с ранее полученной ссылкой и убедиться, что Ссылка.ПолучитьОбъект() возвращает объект, а не Неопределено.

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

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

Сравнение ссылок
Норма

Объект.Ссылка равна ссылке, полученной до записи

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

Ссылки различаются — объект был пересоздан или записан другой копией

ПолучитьОбъект() по ссылке
Норма

Возвращает объект с заполненными реквизитами

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

Возвращает Неопределено — объект не записан, ссылка битая

Запрос по ссылке в таблицу
Норма

Запрос возвращает одну строку

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

Пустой результат — записи в базе нет

Если объект со ссылкой, разошедшейся по другим объектам, так и не был записан (например, из-за исключения в середине алгоритма), в базе останутся ссылки на несуществующий объект. В интерфейсе они отображаются как «Объект не найден». Поэтому создание и запись связанных объектов следует выполнять в транзакции:

bsl
НачатьТранзакцию();
Попытка
    НовыйКонтрагент.Записать();
    Договор.Записать();
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение ОписаниеОшибки();
КонецПопытки;

Ограничения и риски механизма

Метод УстановитьСсылкуНового() нельзя вызвать для объекта, который уже записан, — он предназначен только для новых объектов. Попытка установить ссылку, уже занятую другим объектом того же типа, приведет к ошибке уникальности при записи.

При работе в распределенных базах и при обмене учитывайте, что коллизия GUID маловероятна, но теоретически возможна при ручной генерации идентификаторов. Если вы формируете GUID сами, используйте конструктор Новый УникальныйИдентификатор() без параметров — он создает случайный идентификатор, а не повторяйте «красивые» значения вручную.

Еще одно ограничение: ссылка, полученная через ПолучитьСсылку() у менеджера с GUID, не проверяет существование объекта. Это просто значение-ссылка. Ответственность за то, что объект с таким идентификатором будет записан, лежит на разработчике.

Типичные ошибки при работе со ссылками новых объектов

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

Отдельно стоит упомянуть обращение к реквизитам через точку от ссылки до записи объекта. Выражение вида НоваяСсылка.Наименование заставляет платформа выполнить запрос к базе, где записи еще нет. До записи читайте данные из самого объекта (НовыйЭлемент.Наименование), а не через ссылку.

При массовой загрузке удобно сначала собрать все ссылки будущих объектов в соответствие (ключ — GUID из источника, значение — новая ссылка), а потом в одном проходе создавать объекты и подставлять связи. Так алгоритм остается однопроходным и легко откатывается транзакцией.
ПЗ
Практическое замечание

Когда лучше сначала записать объект

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

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

Маршрут решения

Как выбрать действие

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

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

Ссылка несуществующего объекта строится из уникального идентификатора: ПолучитьСсылку() у нового объекта возвращает его будущую ссылку, а связка Менеджер.ПолучитьСсылку(GUID) и УстановитьСсылкуНового() позволяет назначить заранее известный идентификатор. Записывайте связанные объекты в транзакции и проверяйте результат, чтобы не оставить в базе битые ссылки.

Частые вопросы

Можно ли получить ссылку объекта, который еще ни разу не создавался в коде?

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

Чем ПолучитьСсылку() у объекта отличается от ПолучитьСсылку() у менеджера?

Метод объекта не принимает параметров и возвращает ссылку именно этого экземпляра на основе его уже сгенерированного идентификатора. Метод менеджера принимает уникальный идентификатор (или генерирует новый) и строит ссылку из него, не создавая объект.

Что произойдет, если записать объект без УстановитьСсылкуНового после того, как ссылка уже получена?

Ничего страшного: при записи объект получит тот идентификатор, который был ему назначен при создании, и ранее полученная через ПолучитьСсылку() ссылка совпадет с итоговой. Проблемы возникают только если объект не записать вовсе.

Как найти битые ссылки, если объект все же не был записан?

Битая ссылка определяется тем, что ПолучитьОбъект() по ней возвращает Неопределено. Для поиска по всей базе используют запросы с соединением таблиц по ссылочному полю и проверкой на NULL, либо типовые обработки поиска и удаления помеченных объектов с контролем ссылочной целостности.

Работает ли этот механизм на клиенте в управляемых формах?

ПолучитьСсылку() и УстановитьСсылкуНового() — серверные методы объектной модели. В управляемом приложении их вызывают в серверных процедурах; на тонком клиенте объектная модель справочников и документов недоступна напрямую.

Можно ли изменить ссылку уже записанного объекта?

Нет, ссылка записанного объекта неизменна — это его идентификатор в базе. Если нужен объект с другим GUID, создают новый объект с требуемой ссылкой через УстановитьСсылкуНового(), переносят данные и заменяют ссылки в связанных записях, после чего старый объект удаляют.