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