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

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

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

Как получить ссылку на документ в форме 1С: через Объект.Ссылка, ДанныеФормыВЗначение, в управляемых и обычных формах. Примеры кода, ошибки и проверка результата.

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

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

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

Как устроено хранение данных документа в форме

Чтобы осознанно выбирать способ получения ссылки, важно понимать, что именно лежит в реквизитах формы. В управляемой форме основной реквизит Объект имеет тип «ДанныеФормыСтруктура» на основе объекта «ДокументОбъект». Это сериализуемое представление данных, пригодное для передачи между клиентом и сервером, но не сам объект базы данных. У этого представления доступны все реквизиты документа, включая системное поле Ссылка.

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

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

Получение ссылки в управляемой форме документа

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

&НаКлиенте

Процедура ПоказатьСсылку(Команда)

ТекущаяСсылка = Объект.Ссылка;

Если ТекущаяСсылка.Пустая() Тогда

Сообщить("Документ ещё не записан, ссылка отсутствует");

Иначе

Сообщить("Ссылка: " + Строка(ТекущаяСсылка));

КонецЕсли;

КонецПроцедуры

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

Обратите внимание: свойство Ссылка доступно и на клиенте, и на сервере, потому что это просто данные реквизита формы. Никакого серверного вызова для чтения ссылки не требуется — это важно для производительности тонкого клиента и веб-клиента.

Получение ссылки на сервере через ДанныеФормыВЗначение

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

&НаСервере

Функция ПолучитьСсылкуНаСервере()

ДокОбъект = РеквизитФормыВЗначение("Объект");

Возврат ДокОбъект.Ссылка;

КонецФункции

Этот приём избыточен, если нужна только ссылка, — проще прочитать Объект.Ссылка напрямую. Преобразование РеквизитФормыВЗначение оправдано, когда дальше требуется работа с методами ДокументОбъект: записью, проведением, проверкой заполнения. Учитывайте, что вызов создаёт копию объекта, и изменения в ней не попадут в форму без обратного преобразования ЗначениеВРеквизитФормы.

Ссылка у нового, ещё не записанного документа

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

Первый путь — записать документ и работать со ссылкой после записи, в обработчике ПослеЗаписи. Это самый надёжный вариант, потому что ссылка уже закреплена в базе и не изменится:

&НаКлиенте

Процедура ПослеЗаписи(ПараметрыЗаписи)

СсылкаНаДокумент = Объект.Ссылка;

// дальнейшие действия: открыть форму по ссылке, передать в отчёт и т.д.

КонецПроцедуры

Второй путь — назначить ссылку заранее на сервере через УстановитьСсылкуНового. Тогда документ при записи получит именно эту ссылку, и её можно использовать в других объектах до записи самого документа:

&НаСервере

Процедура УстановитьСсылкуНовогоДокумента()

Если Объект.Ссылка.Пустая() Тогда

ДокОбъект = РеквизитФормыВЗначение("Объект");

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

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

ЗначениеВРеквизитФормы(ДокОбъект, "Объект");

КонецЕсли;

КонецПроцедуры

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

Получение ссылки в обычной форме

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

// В модуле обычной формы документа

Процедура КнопкаСсылкаНажатие(Элемент)

ТекущаяСсылка = Ссылка; // реквизит формы, связанный с объектом

Если Не ЗначениеЗаполнено(ТекущаяСсылка) Тогда

Предупреждение("Документ не записан");

КонецЕсли;

КонецПроцедуры

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

Если ЭтоНовый() Тогда

// ссылка ещё не назначена, документ не записан

КонецЕсли;

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

Ссылка на документ из формы списка и из произвольной формы

В форме списка документов ссылка берётся из текущей строки динамического списка. Обязательно проверяйте, что строка выбрана, иначе получите ошибку обращения к Неопределено:

&НаКлиенте

Процедура ОткрытьВыбранный(Команда)

ТекДанные = Элементы.Список.ТекущиеДанные;

Если ТекДанные = Неопределено Тогда

Возврат;

КонецЕсли;

СсылкаНаДокумент = ТекДанные.Ссылка;

ОткрытьЗначение(СсылкаНаДокумент);

КонецПроцедуры

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

Порядок действий для типовой задачи
  1. 1
    Определите тип формы: управляемая или обычная.
  2. 2
    В управляемой форме прочитайте Объект.Ссылка; в обычной — реквизит Ссылка.
  3. 3
    Проверьте ссылку на пустоту методом Пустая() или ЗначениеЗаполнено().
  4. 4
    Если документ новый — перенесите логику в обработчик ПослеЗаписи.
  5. 5
    Проверьте результат: сообщите ссылку или используйте её в тестовом запросе.

Передача ссылки между клиентом и сервером

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

&НаКлиенте

Процедура ПроверитьПроведение(Команда)

Результат = ПроверитьПроведениеНаСервере(Объект.Ссылка);

Сообщить(Результат);

КонецПроцедуры

&НаСервереБезКонтекста

Функция ПроверитьПроведениеНаСервере(ДокСсылка)

Возврат "Проведён: " + ДокСсылка.Проведен;

КонецФункции

Обратите внимание на приём с &НаСервереБезКонтекста: раз ссылка — это самодостаточное значение, серверной процедуре не нужен контекст формы. Через точку от ссылки (ДокСсылка.Проведен, ДокСсылка.Номер, ДокСсылка.Дата) доступны реквизиты документа — платформа неявно выполняет запрос к базе. Это удобно для одиночных обращений, но в циклах такие обращения порождают множество запросов и резко снижают производительность; там правильнее использовать явный запрос.

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

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

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

Сообщить(Строка(ТекущаяСсылка) + " | " + ТекущаяСсылка.УникальныйИдентификатор());

У пустой ссылки уникальный идентификатор состоит из нулей — это явный признак того, что документ не записан. Дополнительно полезно проверить, что ссылка указывает на реально существующий объект, особенно если она пришла извне: функция ОбщегоНазначения.СсылкаСуществует в типовых конфигурациях или собственный запрос с проверкой ЕСТЬ NULL.

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

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

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

Выводится вид документа и номер, например «Реализация ... 000001 от ...»

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

Пустая строка или «Объект не найден»

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

Ненулевой GUID

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

GUID из одних нулей — ссылка пустая

Использование в запросе
Норма

Запрос с параметром-ссылкой возвращает строки

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

Пустая выборка при заведомо существующих данных

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

Почему Объект.Ссылка возвращает пустое значение?

Документ открыт в режиме создания и ещё ни разу не записывался. Постоянная ссылка появляется только после записи. Перенесите логику в обработчик ПослеЗаписи или принудительно запишите документ методом Записать() перед получением ссылки.

Можно ли получить ссылку на клиенте без вызова сервера?

Да. Объект.Ссылка — это данные реквизита формы, доступные и в клиентском контексте. Серверный вызов нужен только если дальше требуется объект документа или запрос к базе по этой ссылке.

Как получить ссылку на текущий документ в форме списка?

Через Элементы.Список.ТекущиеДанные.Ссылка, предварительно проверив, что ТекущиеДанные не равны Неопределено. Для нескольких выделенных строк используйте Элементы.Список.ВыделенныеСтроки — там каждый элемент уже является ссылкой.

Чем ЭтоНовый() отличается от проверки ссылки на пустоту?

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

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

На сервере преобразуйте реквизит формы в объект, создайте ссылку через Документы.<Имя>.ПолучитьСсылку(Новый УникальныйИдентификатор) и назначьте её методом УстановитьСсылкуНового. Учтите риск «висячих» ссылок, если пользователь не запишет документ.

Можно ли передать ссылку в серверную процедуру с директивой БезКонтекста?

Да, ссылки документов сериализуются и свободно передаются между клиентом и сервером. Вариант с &НаСервереБезКонтекста предпочтителен: процедура не зависит от данных формы и работает быстрее, чем контекстный серверный вызов.

Итог

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

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