Разработка и Конфигурация · 12 мин
Как получить ссылку на документ в форме 1С
Как получить ссылку на документ в форме 1С: через Объект.Ссылка, ДанныеФормыВЗначение, в управляемых и обычных формах. Примеры кода, ошибки и проверка результата.
При разработке и доработке конфигураций 1С часто требуется получить ссылку на документ прямо в модуле формы — например, чтобы передать её в запрос, использовать в отборе регистра, вывести в сообщение или сохранить в параметр. Способ получения зависит от типа формы (управляемая или обычная) и от того, открыт ли документ уже записанным или только создаётся.
Ключевой момент, который нужно понимать сразу: в управляемой форме документа данные хранятся в реквизите Объект типа «ДанныеФормыСтруктура», а не как объект ДокументОбъект. Поэтому прямой вызов методов объекта недоступен, но ссылка при этом получается элементарно — через свойство Объект.Ссылка. Сложности начинаются с новыми, ещё не записанными документами: у них ссылка либо пустая, либо временная (если была установлена программно).
Ниже разобраны рабочие способы для управляемых и обычных форм, варианты получения ссылки у нового документа, передача ссылки между клиентом и сервером, а также типичные ошибки, из-за которых код возвращает пустое значение или падает с ошибкой.
Как устроено хранение данных документа в форме
Чтобы осознанно выбирать способ получения ссылки, важно понимать, что именно лежит в реквизитах формы. В управляемой форме основной реквизит Объект имеет тип «ДанныеФормыСтруктура» на основе объекта «ДокументОбъект». Это сериализуемое представление данных, пригодное для передачи между клиентом и сервером, но не сам объект базы данных. У этого представления доступны все реквизиты документа, включая системное поле Ссылка.
В обычной форме (толстый клиент, режим обычного приложения) ситуация проще: реквизит формы напрямую связан с объектом ДокументОбъект, и доступ к нему выполняется через методы формы без промежуточных преобразований. Код из обычной формы нельзя переносить в управляемую без адаптации — типичная причина ошибок при миграции конфигураций.
Отдельный случай — форма списка документов. Там реквизита Объект нет, а ссылку нужно брать из текущей строки динамического списка: Элементы.Список.ТекущиеДанные.Ссылка. При этом, если ни одна строка не выбрана, обращение вернёт Неопределено, что нужно проверять перед использованием.
Получение ссылки в управляемой форме документа
Самый частый сценарий — получить ссылку в модуле управляемой формы документа, например в обработчике команды, при открытии или перед записью. Для этого достаточно обратиться к свойству Ссылка реквизита Объект:
&НаКлиенте
Процедура ПоказатьСсылку(Команда)
ТекущаяСсылка = Объект.Ссылка;
Если ТекущаяСсылка.Пустая() Тогда
Сообщить("Документ ещё не записан, ссылка отсутствует");
Иначе
Сообщить("Ссылка: " + Строка(ТекущаяСсылка));
КонецЕсли;
КонецПроцедуры
Метод Пустая() у ссылки — обязательная проверка. Если документ открыт в режиме создания и ни разу не записывался, Объект.Ссылка вернёт пустую ссылку соответствующего типа. Передача такой ссылки в запрос или в параметр другой процедуры даст пустые выборки и логические ошибки, которые трудно отловить.
Обратите внимание: свойство Ссылка доступно и на клиенте, и на сервере, потому что это просто данные реквизита формы. Никакого серверного вызова для чтения ссылки не требуется — это важно для производительности тонкого клиента и веб-клиента.
Получение ссылки на сервере через ДанныеФормыВЗначение
Если в серверной процедуре нужен не просто указатель, а сам объект документа (например, для программной дозаписи или проверки движений), реквизит формы преобразуется в объект:
&НаСервере
Функция ПолучитьСсылкуНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
Возврат ДокОбъект.Ссылка;
КонецФункции
Этот приём избыточен, если нужна только ссылка, — проще прочитать Объект.Ссылка напрямую. Преобразование РеквизитФормыВЗначение оправдано, когда дальше требуется работа с методами ДокументОбъект: записью, проведением, проверкой заполнения. Учитывайте, что вызов создаёт копию объекта, и изменения в ней не попадут в форму без обратного преобразования ЗначениеВРеквизитФормы.
Ссылка у нового, ещё не записанного документа
Главная проблема темы: до первой записи у документа нет постоянной ссылки. Если бизнес-логика требует знать ссылку заранее — например, чтобы связать с документом файлы или строки другого объекта до записи — есть два корректных пути.
Первый путь — записать документ и работать со ссылкой после записи, в обработчике ПослеЗаписи. Это самый надёжный вариант, потому что ссылка уже закреплена в базе и не изменится:
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
СсылкаНаДокумент = Объект.Ссылка;
// дальнейшие действия: открыть форму по ссылке, передать в отчёт и т.д.
КонецПроцедуры
Второй путь — назначить ссылку заранее на сервере через УстановитьСсылкуНового. Тогда документ при записи получит именно эту ссылку, и её можно использовать в других объектах до записи самого документа:
&НаСервере
Процедура УстановитьСсылкуНовогоДокумента()
Если Объект.Ссылка.Пустая() Тогда
ДокОбъект = РеквизитФормыВЗначение("Объект");
НоваяСсылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Новый УникальныйИдентификатор);
ДокОбъект.УстановитьСсылкуНового(НоваяСсылка);
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецЕсли;
КонецПроцедуры
Риск этого подхода в том, что документ может так и не быть записан — пользователь закроет форму. Тогда в базе останутся «висячие» ссылки из других объектов на несуществующий документ. Поэтому предустановленную ссылку применяют только там, где логика это явно требует и предусмотрена очистка связей.
Получение ссылки в обычной форме
В обычных формах (конфигурации на управляемом приложении 8.2, а также режим обычного приложения) объект документа доступен напрямую. Ссылка получается через реквизит формы либо через метод объекта:
// В модуле обычной формы документа
Процедура КнопкаСсылкаНажатие(Элемент)
ТекущаяСсылка = Ссылка; // реквизит формы, связанный с объектом
Если Не ЗначениеЗаполнено(ТекущаяСсылка) Тогда
Предупреждение("Документ не записан");
КонецЕсли;
КонецПроцедуры
Также в обычной форме доступен метод ПолучитьОбъект() не нужен — объект уже связан с формой, и обращение ЭтотОбъект.Ссылка или просто Ссылка работает напрямую. Проверка на новый документ выполняется через ЭтоНовый():
Если ЭтоНовый() Тогда
// ссылка ещё не назначена, документ не записан
КонецЕсли;
Метод ЭтоНовый() предпочтительнее сравнения ссылки с пустой: он однозначно отражает состояние объекта и не зависит от того, была ли ссылка назначена программно через УстановитьСсылкуНового.
Ссылка на документ из формы списка и из произвольной формы
В форме списка документов ссылка берётся из текущей строки динамического списка. Обязательно проверяйте, что строка выбрана, иначе получите ошибку обращения к Неопределено:
&НаКлиенте
Процедура ОткрытьВыбранный(Команда)
ТекДанные = Элементы.Список.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Возврат;
КонецЕсли;
СсылкаНаДокумент = ТекДанные.Ссылка;
ОткрытьЗначение(СсылкаНаДокумент);
КонецПроцедуры
Если ссылка нужна в произвольной форме (обработка, отчёт), она обычно приходит как параметр формы. При открытии формы с параметром Ключ платформа сама подставит ссылку; в обработчике ПриСозданииНаСервере её читают из Параметры.Ключ или из переданной структуры параметров. Для надёжности проверяйте тип полученного значения функцией ТипЗнч, прежде чем использовать его в запросах.
- 1Определите тип формы: управляемая или обычная.
- 2В управляемой форме прочитайте Объект.Ссылка; в обычной — реквизит Ссылка.
- 3Проверьте ссылку на пустоту методом Пустая() или ЗначениеЗаполнено().
- 4Если документ новый — перенесите логику в обработчик ПослеЗаписи.
- 5Проверьте результат: сообщите ссылку или используйте её в тестовом запросе.
Передача ссылки между клиентом и сервером
Ссылки на документы относятся к типам, которые свободно передаются между клиентом и сервером в управляемом приложении. Это значит, что Объект.Ссылка можно передавать параметром в серверные процедуры без ограничений:
&НаКлиенте
Процедура ПроверитьПроведение(Команда)
Результат = ПроверитьПроведениеНаСервере(Объект.Ссылка);
Сообщить(Результат);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьПроведениеНаСервере(ДокСсылка)
Возврат "Проведён: " + ДокСсылка.Проведен;
КонецФункции
Обратите внимание на приём с &НаСервереБезКонтекста: раз ссылка — это самодостаточное значение, серверной процедуре не нужен контекст формы. Через точку от ссылки (ДокСсылка.Проведен, ДокСсылка.Номер, ДокСсылка.Дата) доступны реквизиты документа — платформа неявно выполняет запрос к базе. Это удобно для одиночных обращений, но в циклах такие обращения порождают множество запросов и резко снижают производительность; там правильнее использовать явный запрос.
Обращение к реквизитам через точку от ссылки (Ссылка.Номер) на сервере — это скрытый запрос к базе. Для одного-двух обращений это нормально, но в цикле по сотне документов замените его одним запросом с выборкой нужных полей.
Проверка результата и типичные ошибки
После получения ссылки убедитесь, что она корректна. Простейшая проверка — вывести строковое представление и уникальный идентификатор:
Сообщить(Строка(ТекущаяСсылка) + " | " + ТекущаяСсылка.УникальныйИдентификатор());
У пустой ссылки уникальный идентификатор состоит из нулей — это явный признак того, что документ не записан. Дополнительно полезно проверить, что ссылка указывает на реально существующий объект, особенно если она пришла извне: функция ОбщегоНазначения.СсылкаСуществует в типовых конфигурациях или собственный запрос с проверкой ЕСТЬ NULL.
Как проверить результат
Выводится вид документа и номер, например «Реализация ... 000001 от ...»
Пустая строка или «Объект не найден»
Ненулевой GUID
GUID из одних нулей — ссылка пустая
Запрос с параметром-ссылкой возвращает строки
Пустая выборка при заведомо существующих данных
Частые вопросы
Почему Объект.Ссылка возвращает пустое значение?
Документ открыт в режиме создания и ещё ни разу не записывался. Постоянная ссылка появляется только после записи. Перенесите логику в обработчик ПослеЗаписи или принудительно запишите документ методом Записать() перед получением ссылки.
Можно ли получить ссылку на клиенте без вызова сервера?
Да. Объект.Ссылка — это данные реквизита формы, доступные и в клиентском контексте. Серверный вызов нужен только если дальше требуется объект документа или запрос к базе по этой ссылке.
Как получить ссылку на текущий документ в форме списка?
Через Элементы.Список.ТекущиеДанные.Ссылка, предварительно проверив, что ТекущиеДанные не равны Неопределено. Для нескольких выделенных строк используйте Элементы.Список.ВыделенныеСтроки — там каждый элемент уже является ссылкой.
Чем ЭтоНовый() отличается от проверки ссылки на пустоту?
ЭтоНовый() показывает, что объект ещё не записан в базу. Ссылка при этом может быть заранее назначена через УстановитьСсылкуНового и быть непустой. Если важен факт записи в базу — используйте ЭтоНовый(); если важно наличие идентификатора — проверяйте ссылку.
Как получить ссылку на документ, который ещё не создан, для связи с другими объектами?
На сервере преобразуйте реквизит формы в объект, создайте ссылку через Документы.<Имя>.ПолучитьСсылку(Новый УникальныйИдентификатор) и назначьте её методом УстановитьСсылкуНового. Учтите риск «висячих» ссылок, если пользователь не запишет документ.
Можно ли передать ссылку в серверную процедуру с директивой БезКонтекста?
Да, ссылки документов сериализуются и свободно передаются между клиентом и сервером. Вариант с &НаСервереБезКонтекста предпочтителен: процедура не зависит от данных формы и работает быстрее, чем контекстный серверный вызов.
Что важно запомнить
В управляемой форме ссылка читается как Объект.Ссылка прямо на клиенте, в обычной — через реквизит Ссылка. У нового документа ссылки нет до записи: работайте в обработчике ПослеЗаписи или назначайте ссылку заранее осознанно. Всегда проверяйте ссылку на пустоту перед использованием в запросах и передаче в другие процедуры.