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