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

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

Как в 1С обратиться к реквизиту другого документа

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

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

Главная ошибка новичков — путать ссылку на документ и сам документ. Ссылка — это только идентификатор, указатель на запись в базе. Чтобы прочитать реквизиты, нужно либо обратиться к ним «через точку» (платформа неявно считает объект), либо получить объект явно методом ПолучитьОбъект(), либо выбрать данные запросом. Выбор зависит от того, где выполняется код: на сервере, на клиенте, в модуле объекта или в форме.

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

Через точку от ссылки — самый простой способ

Если у вас есть ссылка на документ (например, реквизит «ДокументОснование» текущего документа), реквизиты читаются прямо через точку:

КонтрагентОснования = ДокументОснование.Контрагент;

НомерОснования = ДокументОснование.Номер;

ДатаОснования = ДокументОснование.Дата;

Платформа при первом обращении через точку неявно считывает объект из базы и кэширует его. Это удобно для одного-двух реквизитов, но каждое обращение к новой ссылке — отдельное обращение к базе данных. Если в цикле обходится тысяча документов и для каждого читается реквизит через точку, получится тысяча запросов к СУБД — код будет работать медленно.

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

Чтение реквизитов запросом — для массовой обработки

Когда нужно прочитать реквизиты нескольких документов или несколько реквизитов сразу, правильный инструмент — запрос. Один запрос к базе вместо множества обращений через точку:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Реализация.Номер,

| Реализация.Дата,

| Реализация.Контрагент,

| Реализация.СуммаДокумента

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ДокументОснование);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

КонтрагентОснования = Выборка.Контрагент;

КонецЕсли;

Запрос — единственный способ, который не требует прав на чтение всего объекта целиком в некоторых сценариях RLS и позволяет выбрать только нужные поля. Кроме того, запросом можно сразу получить данные табличной части другого документа, обратившись к таблице вида Документ.РеализацияТоваровУслуг.Товары.

Признак правильного решения: если в коде есть цикл по коллекции ссылок и внутри цикла обращение через точку — перепишите на запрос с условием Ссылка В (&СписокСсылок). Выигрыш в скорости будет кратным.

Сравнение способов

Через точку от ссылки

Подходит для 1–3 реквизитов одного документа. Минусы: отдельное обращение к базе на каждую ссылку, неявные серверные вызовы на клиенте.

Запрос

Оптимален для множества документов и табличных частей. Требует написания текста запроса, но выполняется одним обращением к СУБД.

ПолучитьОбъект()

Нужен только для изменения и записи документа. Для чтения избыточен: считывает объект целиком, включая все табличные части, и требует больше памяти.

ПолучитьОбъект() — когда нужно менять данные

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

ДокОбъект = ДокументОснование.ПолучитьОбъект();

ДокОбъект.Комментарий = "Обработан " + ТекущаяДатаСеанса();

ДокОбъект.Записать();

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

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

Обращение к реквизитам документа в форме

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

&НаКлиенте

Процедура ДокументОснованиеПриИзменении(Элемент)

ЗаполнитьПоОснованию();

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

&НаСервере

Процедура ЗаполнитьПоОснованию()

Если ЗначениеЗаполнено(Объект.ДокументОснование) Тогда

Объект.Контрагент = Объект.ДокументОснование.Контрагент;

КонецЕсли;

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

В модуле объекта документа (например, в обработчике ОбработкаЗаполнения) обращение к реквизитам основания ещё проще — параметр ДанныеЗаполнения уже содержит ссылку, и реквизиты читаются через точку или запросом.

Табличная часть другого документа

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

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Номенклатура,

| Товары.Количество

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

|ГДЕ

| Товары.Ссылка = &Ссылка";

bsl
// Безопасное чтение реквизита с проверкой
Если ЗначениеЗаполнено(ДокументОснование) Тогда
	Контрагент = ДокументОснование.Контрагент;
Иначе
	Контрагент = Неопределено;
КонецЕсли;

Проверка существования и битые ссылки

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

Запрос = Новый Запрос(

"ВЫБРАТЬ ПЕРВЫЕ 1 ИСТИНА

|ИЗ Документ.РеализацияТоваровУслуг КАК Д

|ГДЕ Д.Ссылка = &Ссылка");

Запрос.УстановитьПараметр("Ссылка", ДокументОснование);

ДокументСуществует = НЕ Запрос.Выполнить().Пустой();

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

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

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

Значение реквизита после чтения
Норма

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

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

Пустое значение при заведомо заполненном реквизите — возможно, битая ссылка

Скорость обработки цикла по документам
Норма

Обход тысячи документов занимает секунды, один запрос к СУБД

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

Каждая итерация дёргает базу через точку — видно в замере производительности

Права пользователя
Норма

Чтение выполняется без ошибок под рабочей учётной записью

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

Ошибка «Нарушение прав доступа» — у роли нет права Чтение на вид документа

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

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

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

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

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

Можно ли обратиться к реквизиту документа, не открывая его форму?

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

Чем отличается Ссылка от Объекта в 1С?

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

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

Через точку от ссылки табличная часть недоступна. Используйте запрос к таблице вида Документ.ИмяДокумента.ИмяТабличнойЧасти с отбором по ссылке, либо получите объект и обратитесь к табличной части как к коллекции строк.

Почему обращение через точку возвращает пустое значение, хотя реквизит заполнен?

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

Можно ли обратиться к реквизиту документа другой информационной базы?

Напрямую через точку — нет, ссылки работают только внутри одной базы. Для межбазового доступа используют COM-соединение, веб-сервисы, HTTP-сервисы или планы обмена. Во внешнем соединении логика та же: ссылка в контексте той базы, затем чтение реквизитов.

Что быстрее: обращение через точку или запрос?

Для одного реквизита одного документа разница несущественна. Для нескольких документов или нескольких реквизитов запрос всегда быстрее, так как выполняется одним обращением к СУБД, тогда как каждое обращение через точку к новой ссылке — отдельное чтение.

Итог

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

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