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