Как исправить ошибку "Значение не является значением объектного типа" при вызове метода "ВыгрузитьЗначения" в отчетах 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разберем одну из распространенных и иногда весьма запутанных ошибок в разработке отчетов на Системе Компоновки Данных (СКД) в 1С:Предприятие – "Значение не является значением объектного типа" при попытке вызова метода ВыгрузитьЗначения(). Эта ошибка часто возникает при получении пользовательских параметров отчета и может привести в замешательство, особенно когда отчет стабильно работает в одной базе, но падает в другой.

Предположим, вы разрабатываете внешний отчет, добавляете в него новое поле, тестируете в тестовой базе – все отлично. Переносите в рабочую базу, запускаете, и тут появляется ошибка: "Значение не является значением объектного типа(ВыгрузитьЗначения)". Рассмотрим подробнее, что это за ошибка, почему она возникает и как ее эффективно диагностировать и устранить.

Понимание ошибки "Значение не является значением объектного типа" и метода "ВыгрузитьЗначения"

Метод ВыгрузитьЗначения() в 1С используется для получения содержимого коллекций значений, таких как СписокЗначений, Массив или ТаблицаЗначений, в виде массива или списка для дальнейшей обработки. Когда система выдает ошибку "Значение не является значением объектного типа", это означает, что переменная, на которой вы пытаетесь вызвать этот метод, либо не инициализирована (ее значение Неопределено), либо содержит значение примитивного типа (например, строка, число, дата), которое, очевидно, не имеет метода ВыгрузитьЗначения().

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    // ...
    ПараметрыЗапроса = Новый Структура("ПоставГамбург,Постав6Проц,ОсновКлиенты");
    Для Каждого ЭлмПарам Из ПараметрыЗапроса Цикл
        ПарамСКД = ПолучитьПользовательскийПараметр(ЭлмПарам.Ключ, КомпоновщикНастроек);
        Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
            ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения); // <-- ОШИБКА ЗДЕСЬ
        Иначе
            ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение);
        КонецЕсли;
    КонецЦикла;
    // ...
КонецПроцедуры

В этом коде ошибка возникает в строке ПарамСКД.Значение.ВыгрузитьЗначения;. Это происходит потому, что ПарамСКД.Значение в этот момент не является объектом, поддерживающим метод ВыгрузитьЗначения. Чаще всего это случается по одной из следующих причин:

  1. Параметр не установлен: Пользователь не выбрал значение для параметра в форме отчета, и ПолучитьПользовательскийПараметр() возвращает объект, у которого свойство Значение равно Неопределено.
  2. Несоответствие типов: Параметр в СКД определен как примитивный тип (например, Строка), но код ожидает, что он будет СписокЗначений или аналогичной коллекцией. Если пользователь выбрал только одно значение для параметра, который *может* быть списком, ПарамСКД.Значение может содержать не СписокЗначений, а само это единственное значение, и тогда ВыгрузитьЗначения() будет неприменимо.
  3. Ошибка при получении параметра: Параметр с указанным ключом отсутствует в настройках компоновщика, и ПолучитьПользовательскийПараметр() возвращает Неопределено.
  4. Проблемы с кэшированием: 1С активно кэширует внешние отчеты и их настройки. Если вы внесли изменения в отчет, но 1С продолжает использовать старую, закэшированную версию, это может привести к тому, что параметры, которые должны быть установлены, воспринимаются как Неопределено или имеют некорректный тип, поскольку новая логика работы с ними еще не применена. В случае, описанном в исходной теме, именно кэширование оказалось главной причиной проблемы.
  5. Проблемы с отладкой: Невозможность поставить точку останова и посмотреть значение переменной существенно затрудняет диагностику.

Диагностика проблемы: Где именно "не объект"?

Первый шаг к решению проблемы – это понять, какое именно значение является "не объектным".

1. Проверка значений переменных в коде

Если отладка работает корректно, установите точку останова прямо перед строкой, вызывающей ошибку:


Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
    // Установите точку останова здесь
    ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения);
// ...

Затем, во время выполнения, посмотрите значения ЭлмПарам.Ключ, ПарамСКД и, самое главное, ПарамСКД.Значение. Вы увидите, что ПарамСКД.Значение, скорее всего, будет Неопределено или каким-то примитивным типом (например, Строка, если пользователь выбрал один элемент из списка, а не сам СписокЗначений).

Если отладка по какой-то причине не работает (что часто бывает с внешними отчетами или на сервере), воспользуйтесь функцией Сообщить():


Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
    Сообщить("Ключ параметра: " + ЭлмПарам.Ключ);
    Сообщить("Тип значения параметра: " + ТипЗнч(ПарамСКД.Значение));
    Сообщить("Значение параметра: " + Строка(ПарамСКД.Значение)); // Строка() для преобразования
    ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ПарамСКД.Значение.ВыгрузитьЗначения);
// ...

Это поможет нам выяснить, какой именно параметр вызывает проблему и какое значение он имеет.

2. Проблемы с отладкой внешних отчетов и серверного кода

В исходной теме пользователь столкнулся с тем, что точки останова не срабатывают. Это очень частая проблема при отладке внешних отчетов, особенно если они выполняются на сервере 1С:Предприятия. Рассмотрим, почему это происходит и как настроить отладку.

Почему не срабатывает точка останова?

Внешние отчеты, особенно те, что используют СКД, могут выполняться как на клиенте, так и на сервере. Если отчет запускается на сервере (например, в тонком клиенте, веб-клиенте, или как фоновое задание), то для отладки его серверного кода необходимо, чтобы отладка сервера 1С была настроена и активна.

Настройка отладки серверного кода:

  1. Для файловой базы: В файловой базе отладка обычно работает без дополнительных настроек, поскольку клиент и сервер (если он есть, например, в виде фоновых заданий) работают в одном процессе или легко подключаются. Однако, убедитесь, что в конфигураторе в меню "Отладка" -> "Подключение" установлен флажок "Автоматическое подключение фоновых заданий".
  2. Для клиент-серверной базы: Это более сложный случай. Для отладки серверного кода необходимо, чтобы служба сервера 1С:Предприятия была запущена с ключом -debug. Этот ключ разрешает серверу принимать соединения от отладчиков.
    1. Остановка службы: Сначала остановите службу 1С:Предприятия на сервере.
    2. Изменение параметров запуска: Найдите путь к исполняемому файлу службы 1С (обычно ragent.exe или rmngr.exe). Добавьте ключ -debug к параметрам запуска службы. Например, путь может выглядеть так: "C:\Program Files\1cv8\8.3.ХХ.ХХХХ\bin\ragent.exe" -debug.
    3. Запуск службы: Запустите службу 1С:Предприятия снова.
    4. Настройка конфигуратора: В конфигураторе откройте меню "Отладка" -> "Подключение". Убедитесь, что там стоит флажок "Автоматическое подключение фоновых заданий", а также при необходимости вручную подключитесь к процессу сервера, если это не произошло автоматически.

После этих настроек точки останова в серверном коде вашего отчета должны начать срабатывать, позволяя нам увидеть реальные значения переменных и точно определить источник ошибки.

Решение проблемы: Пошаговый подход

Теперь, когда мы понимаем причины и методы диагностики, давайте рассмотрим, как решить проблему "Значение не является значением объектного типа(ВыгрузитьЗначения)".

1. Устранение кэширования внешних отчетов (Основное решение в нашей теме)

Как показал опыт автора темы, одной из самых коварных причин является кэширование 1С. Система может продолжать использовать старую версию отчета, даже если вы загрузили новую. Это приводит к тому, что изменения в коде не применяются, а параметры могут быть Неопределено или иметь некорректный тип, как будто они не были установлены в старой версии отчета.

  1. Переименование отчета: Самый простой и эффективный способ "обмануть" кэш 1С – это переименовать сам внешний отчет.
    • В конфигураторе откройте свойства отчета (нажмите F4, находясь на корневом узле отчета в дереве метаданных) и измените его "Имя".
    • Сохраните отчет и заново откройте его в режиме 1С:Предприятие.

    Если отчет встроен в конфигурацию, но вы его дорабатываете как внешний, после доработки его можно временно переименовать или добавить цифры в имя. Если же это внешний файл (.erf), просто сохраните его под новым именем.

  2. Переименование варианта отчета: Если проблема касается конкретного варианта отчета, который вы сохранили, попробуйте изменить его имя.
    • Откройте отчет в режиме 1С:Предприятие.
    • Перейдите к выбору вариантов отчета, выберите проблемный вариант и измените его "Наименование" (например, добавьте в конце " (тест)").
    • Сохраните изменения в варианте.
  3. Очистка кэша 1С: В более сложных случаях или если переименование не помогло, может потребоваться ручная очистка кэша 1С.
    1. Закройте все сеансы 1С.
    2. Откройте проводник и введите в адресную строку %APPDATA%\1C\1CE\.
    3. В этой папке вы увидите подпапки с длинными буквенно-цифровыми именами. Это и есть кэш 1С для различных баз. Удалите все содержимое этих папок.
    4. Также можно очистить кэш в меню запуска 1С:Предприятия, выбрав базу данных, нажав кнопку "Изменить", и в появившемся окне нажать "Очистить кэш".

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

2. Корректная обработка параметров СКД

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

  1. Проверка на Неопределено и тип данных: Всегда проверяйте, что полученное значение параметра не является Неопределено и имеет ожидаемый тип, прежде чем вызывать специфические методы.
  2. Использование ЗначениеЗаполнено(): Эта функция может быть полезна для проверки, содержит ли параметр хоть какое-то значимое значение.

Давайте улучшим наш код с учетом этих проверок:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ПараметрыЗапроса = Новый Структура("ПоставГамбург,Постав6Проц,ОсновКлиенты");

    Для Каждого ЭлмПарам Из ПараметрыЗапроса Цикл
        ПарамСКД = ПолучитьПользовательскийПараметр(ЭлмПарам.Ключ, КомпоновщикНастроек);
        
        Если ПарамСКД = Неопределено Тогда // Проверяем, что параметр вообще существует
            Сообщить("Внимание: Параметр '" + ЭлмПарам.Ключ + "' не найден в настройках компоновщика.");
            Продолжить; 
        КонецЕсли;

        ЗначениеПараметра = ПарамСКД.Значение;

        Если ЭлмПарам.Ключ="ОсновКлиенты" или ЭлмПарам.Ключ="Постав6Проц" Тогда
            Если ЗначениеПараметра = Неопределено Тогда
                Сообщить("Внимание: Для параметра '" + ЭлмПарам.Ключ + "' не выбрано значение. Использование пустого списка.");
                ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, Новый Массив); // Вставляем пустой массив или список по умолчанию
            ИначеЕсли ТипЗнч(ЗначениеПараметра) = Тип("СписокЗначений") Тогда
                ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра.ВыгрузитьЗначения());
            ИначеЕсли ТипЗнч(ЗначениеПараметра) = Тип("Массив") Тогда // Если уже массив
                ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра);
            Иначе // Если это одно значение, а не список/массив
                Сообщить("Внимание: Для параметра '" + ЭлмПарам.Ключ + "' выбрано одно значение. Преобразуем в массив.");
                ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, Новый Массив({ЗначениеПараметра}));
            КонецЕсли;
        Иначе
            ПараметрыЗапроса.Вставить(ЭлмПарам.Ключ, ЗначениеПараметра);
        КонецЕсли;
    КонецЦикла;

    ПарамСКД = ПолучитьПользовательскийПараметр("ПериодОтчета", КомпоновщикНастроек);
    Если ПарамСКД <> Неопределено И ЗначениеЗаполнено(ПарамСКД.Значение) И ТипЗнч(ПарамСКД.Значение) = Тип("СтандартныйПериод") Тогда
        ПараметрыЗапроса.Вставить("Д1", ПарамСКД.Значение.ДатаНачала);
        ПараметрыЗапроса.Вставить("Д2", ПарамСКД.Значение.ДатаОкончания);
        ПараметрыЗапроса.Вставить("Гран1", Новый Граница(ПарамСКД.Значение.ДатаНачала, ВидГраницы.Включая));
        ПараметрыЗапроса.Вставить("Гран2", Новый Граница(ПарамСКД.Значение.ДатаОкончания, ВидГраницы.Включая));
    Иначе
        // Обработка случая, если период не установлен или неверного типа
        Сообщить("Внимание: Параметр 'ПериодОтчета' не установлен или имеет неверный тип.");
        // Можно установить значения по умолчанию или прервать формирование отчета
    КонецЕсли;

    ПараметрыЗапроса.Вставить("ЭлмПланАДМ", Справочники.Номенклатура.НайтиПоКоду("00-00017779",Ложь)); 
    СписокОшибок = Неопределено; 
    МояТаблица = ПолучитьДопТЗ(ПараметрыЗапроса, СписокОшибок); 
    ВнешниеНаборыДанных = Новый Структура; 
    ВнешниеНаборыДанных.Вставить("ТЗ", МояТаблица); 
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; 
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки, ДанныеРасшифровки); 
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных; 
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки,ВнешниеНаборыДанных,ДанныеРасшифровки); 
    ДокументРезультат.Очистить; 
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; 
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат); 
    ПроцессорВывода.Вывести(ПроцессорКомпоновки); 
    ДокументРезультат.ПоказатьУровеньГруппировокСтрок(1); 
    Если НЕ СписокОшибок=Неопределено Тогда 
        ОбщегоНазначенияКлиентСервер.СообщитьОшибкиПользователю(СписокОшибок); 
    КонецЕсли; 
КонецПроцедуры

В этом улучшенном коде мы:

  1. Проверяем, что ПарамСКД не является Неопределено, прежде чем обращаться к его свойству Значение.
  2. Проверяем, что ЗначениеПараметра не является Неопределено.
  3. Используем ТипЗнч(), чтобы убедиться, что ЗначениеПараметра является СписокЗначений (или Массив), прежде чем вызывать ВыгрузитьЗначения().
  4. Обрабатываем случай, когда для параметра, ожидающего список, выбрано одно значение, преобразуя его в массив из одного элемента.
  5. Добавляем информативные сообщения для пользователя, что помогает в отладке и понимании логики работы отчета.
  6. Аналогичным образом обрабатываем параметр типа СтандартныйПериод, проверяя его наличие и тип перед использованием полей ДатаНачала и ДатаОкончания.

3. Настройка параметров в Схеме Компоновки Данных (СКД)

Убедитесь, что параметры в самой СКД настроены корректно:

  1. Откройте схему компоновки данных.
  2. Перейдите на вкладку "Параметры".
  3. Для параметров, которые должны принимать несколько значений (и для которых вы ожидаете СписокЗначений), установите флажок "Список значений" в свойствах параметра. Это позволит пользователю выбирать несколько значений в форме отчета, и система корректно передаст их как СписокЗначений.
  4. Проверьте тип значения параметра, чтобы он соответствовал тому, что вы ожидаете (например, СправочникСсылка.Номенклатура, СтандартныйПериод и т.д.).

Заключение

Ошибка "Значение не является значением объектного типа(ВыгрузитьЗначения)" является частым спутником разработчиков 1С, работающих с отчетами СКД. Как мы выяснили, причиной может быть как некорректная обработка параметров в коде, так и скрытые механизмы кэширования 1С. Мы рассмотрели:

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

← На главную