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

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

Как получить ссылку на незаписанный документ в 1С

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

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

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

Критически важно понимать ограничение: ссылка на незаписанный документ существует только в оперативной памяти текущего сеанса. До вызова Записать() в базе её нет, и любой другой сеанс или фоновое задание получит по ней «битую» ссылку. Ниже разобраны оба способа, условия их применения, проверка результата и типичные ошибки.

Что происходит с ссылкой до записи документа

При вызове Документы.РеализацияТоваровУслуг.СоздатьДокумент() платформа создаёт объект в памяти и сразу присваивает ему уникальный идентификатор (GUID). Именно этот идентификатор лежит в основе ссылки. Поэтому ссылка на объект существует с момента создания, хотя в таблице базы данных соответствующей строки ещё нет.

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

Однако такая ссылка «висячая»: до записи объекта она ни на что не указывает в физическом хранилище. Если передать её в другой сеанс, записать в регистр или сохранить в файл, а сам документ потом не записать — в базе останется битая ссылка, которую придётся искать и чистить.

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

Самый простой и безопасный вариант — создать объект документа и сразу взять у него ссылку. Этот способ подходит, когда ссылка нужна внутри того же программного блока: например, чтобы заполнить реквизит «ДокументОснование» у связанного документа, который тоже ещё не записан, или чтобы вернуть ссылку из функции, создающей документ.

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();

НовыйДокумент.Дата = ТекущаяДатаСеанса();

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

// СсылкаНаДокумент — полноценное значение типа ДокументСсылка.РеализацияТоваровУслуг

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

Ограничение способа — он не позволяет получить ссылку «отдельно» от объекта. Если нужно сначала сгенерировать ссылку, разослать её по нескольким местам, а объект создать позже, используйте второй способ.

Способ 2: ПолучитьСсылкуНового() и УстановитьСсылкуНового()

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

НоваяСсылка = Документы.ПоступлениеТоваровУслуг.ПолучитьСсылкуНового(Новый УникальныйИдентификатор);

// ... передаём ссылку куда нужно, заполняем связанные данные ...

НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();

НовыйДокумент.УстановитьСсылкуНового(НоваяСсылка);

НовыйДокумент.Дата = ТекущаяДатаСеанса();

НовыйДокумент.Записать();

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

Порядок вызовов строгий: УстановитьСсылкуНового() нужно вызвать до первой записи объекта. После Записать() сменить ссылку уже нельзя — идентификатор зафиксирован в базе.

Порядок действий
  1. 1
    Вызовите Документы.ИмяДокумента.ПолучитьСсылкуНового() — при необходимости передайте GUID из внешней системы
  2. 2
    Используйте полученную ссылку для заполнения реквизитов, регистров или передачи в другие процедуры
  3. 3
    Создайте объект методом СоздатьДокумент() и вызовите УстановитьСсылкуНового(Ссылка)
  4. 4
    Заполните обязательные реквизиты и вызовите Записать()
  5. 5
    Проверьте, что по ссылке читается объект: Ссылка.ПолучитьОбъект() не вернул Неопределено

Когда какой способ выбирать

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

Сравнение вариантов

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

Подходит, когда объект уже создан в коде и ссылка нужна здесь же. Не позволяет задать GUID извне.

ПолучитьСсылкуНового() + УстановитьСсылкуНового()

Подходит для обмена данными и пакетной загрузки, когда ссылка известна заранее. Требует строгого порядка вызовов до записи.

Запись сразу, без работы со ссылкой

Подходит, если ссылка нужна только после записи — тогда достаточно свойства Ссылка у записанного объекта.

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

Проверка результата и диагностика

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

Для анализа уже существующих проблем в базе полезно уметь распознавать битые ссылки. Признак — значение ссылки не пустое, но обращение к реквизитам через точку возвращает Неопределено, а запрос с левым соединением показывает NULL по полям объекта.

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

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

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

Полученная заранее ссылка равна Объект.Ссылка после Записать()

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

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

Чтение объекта по ссылке
Норма

Ссылка.ПолучитьОбъект() возвращает объект документа

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

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

Уникальный идентификатор
Норма

Ссылка.УникальныйИдентификатор() совпадает с GUID из внешней системы при обмене

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

GUID различаются — документы в разных базах не сопоставятся

Ограничения и риски

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

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

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

Типичные ошибки

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

Отдельно выделим ошибку с проверкой «документ существует?». Разработчики иногда пишут Если Не Ссылка.Пустая() Тогда, полагая, что это гарантия наличия документа. Для ссылок, полученных до записи, это неверно: ссылка непустая, а документа в базе нет. Корректная проверка — запросом или через Ссылка.ПолучитьОбъект() с анализом результата на Неопределено.

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

FAQ

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

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

Будет ли ссылка на незаписанный документ видна в другом сеансе?

Нет. До вызова Записать() строки в базе не существует, поэтому другой сеанс, фоновое задание или запрос по этой ссылке получат битую ссылку. Передавать ссылку между сеансами можно только после записи документа.

Как задать документу ссылку с конкретным GUID из другой базы?

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

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

Платформа выдаст ошибку. После первой записи идентификатор документа зафиксирован в базе, и сменить ссылку штатными средствами невозможно.

Как проверить, записан ли документ, по имеющейся ссылке?

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

Итог

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

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