Как исправить ошибку «Недопустимое значение параметра (параметр номер '1')» при заполнении измерений планировщика в 1С?

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

При работе с элементом управления Планировщик в платформе «1С:Предприятие 8» разработчики часто сталкиваются с непредвиденным поведением системы при заполнении его измерений. Одной из наиболее распространенных является ошибка вида: Ошибка при вызове метода контекста (Добавить) по причине: Недопустимое значение параметра (параметр номер '1'). Возникает она в тот момент, когда мы пытаемся программно добавить элементы в коллекцию измерений планировщика.

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

Выясняем причину: почему падает метод Добавить()?

Давайте посмотрим на строку кода, которая вызывает падение системы:

НовыйМастер = ИзмерениеМастера.Элементы.Добавить(выб.Мастер);

Метод Добавить() у коллекции элементов измерения планировщика принимает в качестве первого параметра уникальный идентификатор (ключ) элемента измерения. Чаще всего этим ключом выступает ссылка на элемент справочника (например, ссылка на физическое лицо, сотрудника, склад или, как в нашем случае, мастера).

Ключевая особенность коллекции элементов измерения планировщика заключается в том, что каждый элемент в ней должен быть уникальным. Платформа жестко контролирует уникальность ключей. Если мы пытаемся добавить в измерение ссылку, которая уже присутствует в данной коллекции, платформа не проигнорирует это действие, а незамедлительно вызовет исключение: Недопустимое значение параметра (параметр номер '1').

В коде автора темы выборка из запроса обходит документы «Заявка». Если один и тот же мастер указан в нескольких документах за выбранный период времени, то при обходе выборки в цикле ссылка на этого мастера встретится несколько раз. При первой итерации мастер успешно добавится, а на второй — программа аварийно завершит работу.


Способ 1. Устранение дублей на уровне запроса (Рекомендуемый)

Самый простой, быстрый и производительный способ избежать ошибки — сделать так, чтобы запрос возвращал только уникальные значения для наших измерений. Для этого достаточно использовать ключевое слово РАЗЛИЧНЫЕ в секции ВЫБРАТЬ вашего запроса.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    Заявка.Мастер КАК Мастер
    |ИЗ
    |    Документ.Заявка КАК Заявка
    |ГДЕ
    |    Заявка.Дата МЕЖДУ &ДатаНачало И &ДатаКонец
    |    И Заявка.Мастер <> ЗНАЧЕНИЕ(Справочник.Мастера.ПустаяСсылка)";

Обратите внимание на важное условие в конце запроса. Мы добавили фильтрацию пустых ссылок. Если в документах реквизит «Мастер» окажется незаполненным, пустая ссылка также может вызвать ошибку при добавлении в измерение планировщика. Отсекайте некорректные данные заранее.


Способ 2. Программная проверка на уникальность методом Найти()

Если по каким-то причинам вам необходимо получать полную выборку документов (например, вы параллельно заполняете не только измерения, но и сами события планировщика), то перед добавлением нового элемента в измерение нужно обязательно выполнять проверку на его существование.

Рассмотрим, как правильно реализовать такую проверку в цикле обхода данных:


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

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


Способ 3. Использование таблицы значений и метода Свернуть()

Если данные для планировщика подготавливаются во временных структурах, то можно использовать промежуточную выгрузку в таблицу значений. Этот метод как раз помог автору темы на начальном этапе.

Разберем, как выглядит этот алгоритм:


ТЗ = Запрос.Выполнить().Выгрузить();
// Оставляем в таблице только уникальные строки по колонке "Мастер"
ТЗ.Свернуть("Мастер");

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

Хотя метод со сверткой таблицы значений рабочий, он требует выделения дополнительной оперативной памяти под объект ТаблицаЗначений, поэтому для больших объемов данных предпочтительнее использовать Способ 1.


Критическая архитектурная ошибка: Выполнение запросов на клиенте

Проанализируем исходный код из сообщения автора темы. Процедура Отобразить(Команда) объявлена с директивой компиляции &НаКлиенте. При этом внутри процедуры создается объект Новый Запрос.

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

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

Давайте перепишем код правильно:


&НаКлиенте
Процедура Отобразить(Команда)
    // На клиенте выполняем только интерактивные действия, если они нужны,
    // и передаем управление на сервер
    ОтобразитьНаСервере();
КонецПроцедуры

&НаСервере
Процедура ОтобразитьНаСервере()
    
    // Настройка периодов планировщика
    Планировщик.ТекущиеПериодыОтображения.Очистить();
    Планировщик.ТекущиеПериодыОтображения.Добавить(НачалоДня(ТекущаяДата()), КонецДня(ТекущаяДата()));
    
    Планировщик.ЕдиницаПериодическогоВарианта = ТипЕдиницыШкалыВремени.Час;
    Планировщик.КратностьПериодическогоВарианта = 24;
    Планировщик.ОтображатьПеренесенныеЗаголовки = Истина;
    Планировщик.ОтступСНачалаПереносаШкалыВремени = 8;
    Планировщик.ОтступСКонцаПереносаШкалыВремени = 3;
    
    // Инициализируем измерения планировщика
    ИзмеренияПланировщика = Планировщик.Измерения;
    ИзмеренияПланировщика.Очистить();
    
    ИзмерениеМастера = ИзмеренияПланировщика.Добавить("Мастера");
    
    // Создаем и выполняем запрос на сервере
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    Заявка.Мастер КАК Мастер
        |ИЗ
        |    Документ.Заявка КАК Заявка
        |ГДЕ
        |    Заявка.Дата МЕЖДУ &ДатаНачало И &ДатаКонец
        |    И Заявка.Мастер <> ЗНАЧЕНИЕ(Справочник.Мастера.ПустаяСсылка)";
        
    Запрос.УстановитьПараметр("ДатаНачало", НачалоГода(ТекущаяДата()));
    Запрос.УстановитьПараметр("ДатаКонец", КонецДня(ТекущаяДата()));
    
    Выборка = Запрос.Perform().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        НовыйМастер = ИзмерениеМастера.Элементы.Добавить(Выборка.Мастер);
        НовыйМастер.Текст = Выборка.Мастер.Наименование;
    КонецЦикла;
    
КонецПроцедуры

При таком подходе код работает максимально быстро, не перегружает сетевой трафик между клиентом и сервером и полностью соответствует стандартам разработки фирмы «1С».


Дополнительный совет: Красивое оформление шапки (Платформа 8.3.18+)

Раз уж мы заговорили о заполнении измерений планировщика, рассмотрим современную возможность платформы по кастомизации внешнего вида заголовков. Начиная с версии платформы 8.3.18, свойству Текст элемента измерения планировщика можно присваивать не только простую строку, но и ФорматированнуюСтроку.

Это позволяет делать заголовки интерактивными и визуально привлекательными. Например, вы можете выделить должность мастера серым цветом, а его фамилию сделать жирной:


// Пример создания форматированного заголовка для элемента измерения
МассивЭлементовСтроки = Новый Массив;
МассивЭлементовСтроки.Добавить(Новый ФорматированнаяСтрока("Мастер: ", Новый Шрифт(,,Истина))); // Курсив
МассивЭлементовСтроки.Добавить(Новый ФорматированнаяСтрока(Выборка.Мастер.Наименование, Новый Шрифт(,,,,,Истина))); // Жирный

НовыйМастер.Текст = Новый ФорматированнаяСтрока(МассивЭлементовСтроки);

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

← На главную