При работе с внешними отчетами и обработками в среде «1С:Предприятие 8.3» разработчики и пользователи часто сталкиваются со следующей ошибкой: «{ВнешнийОтчет.ИмяОтчета.МодульОбъекта(НомерСтроки)}: Значение не является значением объектного типа (Значение)». Обычно эта ошибка возникает в момент открытия отчета или при попытке сформировать данные.
В этой статье мы подробно разберем природу данной ошибки, выясним, почему она возникает при программной установке параметров Системы компоновки данных (СКД), и рассмотрим несколько надежных способов ее решения — от быстрого исправления в Конфигураторе до написания отказоустойчивого кода по стандартам разработки фирмы «1С».
Ошибка «Значение не является значением объектного типа» в языке 1С означает, что программа пытается обратиться к свойству или методу переменной, которая на самом деле не является сложным объектом (структурой, справочником, элементом параметров и т.д.), а содержит простейшее значение — чаще всего Неопределено или Null.
Рассмотрим фрагмент исходного кода из темы обсуждения:
Параметры = КомпоновщикНастроек.Настройки.ПараметрыДанных;
ОтборНачПериода = Параметры.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("НачПериода"));
ОтборНачПериода.Значение = НачПериода;
ОтборНачПериода.Использование = Истина;
Давайте проанализируем эту ситуацию по шагам:
КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра() ищет в схеме компоновки данных параметр с уникальным именем "НачПериода".ЗначениеПараметраНастроекКомпоновкиДанных."НачПериода" нет (например, разработчик забыл его добавить, переименовал в запросе или удалил), метод НайтиЗначениеПараметра() возвращает значение Неопределено.ОтборНачПериода.Значение = НачПериода;. Но так как переменная равна Неопределено, у нее нет свойства Значение. Платформа аварийно завершает работу и выдает ошибку.Таким образом, корень проблемы кроется в рассинхронизации между программным кодом инициализации и структурой параметров в самой схеме компоновки данных (СКД).
Самый очевидный и правильный путь исправления — привести структуру схемы компоновки данных в соответствие с тем, что ожидает программный код модуля. Выполним настройку схемы СКД через Конфигуратор:
ОсновнаяСхемаКомпоновкиДанных)."НачПериода" и "КонПериода". Если их там нет, добавьте их, нажав кнопку Добавить (+).НачПериода и КонПериода).Дата.Даже если вы добавили параметры в схему, хорошим тоном в программировании на платформе 1С является обеспечение защиты кода от непредвиденного поведения. Перед тем как обращаться к свойствам объекта, полученного в результате поиска, обязательно нужно делать проверку на Неопределено.
Перепишем исходную процедуру, сделав ее максимально безопасной и стабильной:
Процедура УстановитьПараметры Экспорт
Параметры = КомпоновщикНастроек.Настройки.ПараметрыДанных;
// Безопасная установка Начала периода
ОтборНачПериода = Параметры. НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("НачПериода"));
Если ОтборНачПериода <> Неопределено Тогда
НачПериода = НачалоМесяца(ТекущаяДата());
ОтборНачПериода.Значение = НачПериода;
ОтборНачПериода.Использование = Истина;
КонецЕсли;
// Безопасная установка Конца периода
ОтборКонПериода = Параметры. НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("КонПериода"));
Если ОтборКонПериода <> Неопределено Тогда
КонПериода = КонецМесяца(ТекущаяДата());
ОтборКонПериода.Значение = КонецДня(КонПериода);
ОтборКонПериода.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Благодаря такой проверке, даже если параметры будут случайно удалены из схемы СКД будущими разработчиками, отчет не упадет с критической ошибкой, а продолжит открываться и работать.
Для сокращения объема кода и повышения его читаемости в платформе 1С предусмотрен встроенный метод быстрого присвоения значений параметрам. Вместо трех строк кода (поиск, присвоение значения, включение флага использования) мы можем воспользоваться методом УстановитьЗначениеПараметра().
Проанализируем пример изящного решения:
Процедура УстановитьПараметры Экспорт
// Быстрая установка значений по умолчанию
НачДата = НачалоМесяца(ТекущаяДата());
КонДата = КонецМесяца(ТекущаяДата());
// Установка параметров СКД напрямую
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачПериода", НачДата);
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонПериода", КонецДня(КонДата));
КонецПроцедуры
Важное предупреждение: метод УстановитьЗначениеПараметра() также вызовет ошибку времени выполнения, если указанного параметра нет в схеме компоновки. Поэтому данный метод следует применять только тогда, когда вы абсолютно уверены в неизменности структуры вашей СКД.
Нередко возникает странная ситуация: один пользователь открывает отчет без проблем (например, на другом компьютере или под другой учетной записью), а у второго — падает описанная выше ошибка. Почему так происходит?
Причина кроется в механизме сохранения настроек отчетов. Платформа 1С автоматически кэширует и сохраняет последние использованные настройки отчета для каждого конкретного пользователя. Если отчет запускался ранее, когда структура параметров СКД была другой (или параметры отсутствовали вовсе), старые настройки загружаются из кэша системы и конфликтуют с обновленным программным кодом.
Чтобы решить эту проблему без редактирования кода, пользователю достаточно выполнить сброс настроек к стандартным:
Начиная с версии платформы 8.3, параметры СКД, выведенные на форму отчета, хранятся в специальной коллекции — КомпоновщикНастроек.ПользовательскиеНастройки. Если программист меняет параметры напрямую через КомпоновщикНастроек.Настройки.ПараметрыДанных, эти изменения могут попросту не примениться к элементам на форме, так как приоритет пользовательских настроек выше.
Рассмотрим, как правильно изменять параметры с учетом механизма пользовательских настроек:
// Ищем описание параметра в основных настройках СКД
ПараметрИскомый = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("НачПериода");
Если ПараметрИскомый <> Неопределено Тогда
// Пытаемся найти этот параметр в коллекции пользовательских настроек на форме
ЭлементПользовательскихНастроек = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ПараметрИскомый.ИдентификаторПользовательскойНастройки);
Если ЭлементПользовательскихНастроек <> Неопределено Тогда
// Устанавливаем значение, которое гарантированно отобразится на форме
ЭлементПользовательскихНастроек.Значение = НачалоМесяца(ТекущаяДата());
ЭлементПользовательскихНастроек.Использование = Истина;
КонецЕсли;
КонецЕсли;
Использование этого шаблона кода гарантирует, что программно установленные даты не только корректно запишутся в систему компоновки, но и отобразятся в полях ввода на форме отчета перед глазами пользователя.
В обсуждении на форуме код инициализации вызывается при открытии формы (процедура УстановитьПараметры). Но что произойдет, если отчет будет формироваться программно — например, регламентным заданием по расписанию, в фоновом задании на сервере или при автоматической рассылке отчетов?
В таких сценариях интерактивная форма отчета вообще не создается, а значит, процедура инициализации параметров не будет вызвана, и отчет либо сформируется некорректно, либо завершится с ошибкой.
Правильным архитектурным решением является перенос кода заполнения параметров в модуль объекта отчета, в предопределенный обработчик ПриКомпоновкеРезультата:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Устанавливаем параметры непосредственно перед компоновкой результата
ПараметрыДанных = КомпоновщикНастроек.Настройки.ПараметрыДанных;
ПараметрНач = ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("НачПериода"));
Если ПараметрНач <> Неопределено И Не ЗначениеЗаполнено(ПараметрНач.Значение) Тогда
ПараметрНач.Значение = НачалоМесяца(ТекущаяДата());
ПараметрНач.Использование = Истина;
КонецЕсли;
// Код установки остальных параметров...
КонецПроцедуры
Размещение логики в обработчике ПриКомпоновкеРезультата гарантирует стабильную инициализацию параметров СКД при любых сценариях выполнения отчета: как в ручном режиме пользователем, так и при автоматической генерации данных на сервере.