Как правильно настроить выборку из справочника, сравнить данные с константой, раскрасить ячейки макета и выполнить фильтрацию в 1С?

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

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

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

Проблема 1: Ошибки сравнения типов данных и работы с константами

Рассмотрим исходный фрагмент кода, с которым возникли сложности:


Выборка = Справочники.Сотрудники.Выбрать();
Пока Выборка.Следующий() Цикл
    Наименование = Выборка.Наименование;
    Если Наименование = Константы.Директор Тогда
        // Код обработки макета
    КонецЕсли;
КонецЦикла;

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

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

Во-вторых, несовпадение типов данных при сравнении. Переменная Наименование содержит строковое значение (тип Строка). В то же время константа «Директор» хранит в себе ссылку на элемент справочника (тип СправочникСсылка.Сотрудники). Платформа 1С никогда не приравняет строку к ссылке, поэтому условие в операторе Если всегда будет возвращать значение Ложь.

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


// Сначала получаем ссылку на директора из константы
СсылкаДиректор = Константы.Директор.Получить();

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

Проблема 2: Ошибка «Поле объекта не обнаружено (ЦветФона)»

Следующая сложность возникла при попытке визуального выделения строки в макете:

ОбластьШапка.ЦветФона = WebЦвета.Красный;

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

Дело в том, что переменная ОбластьШапка представляет собой объект типа ОбластьТабличногоДокумента, полученный из макета. У самого объекта именованной области нет прямого свойства ЦветФона. Данное свойство присутствует только у конкретной ячейки или диапазона ячеек, входящих в эту область.

Чтобы покрасить нужные ячейки, нам необходимо обратиться к ним через метод Область(), указав координаты строки и колонки (индексация начинается с 1):


// Пример 1: Изменение цвета фона одной ячейки (строка 1, колонка 1 в пределах области)
ОбластьШапка.Область(1, 1).ЦветФона = WebЦвета.Красный;

// Пример 2: Изменение цвета фона диапазона ячеек (с 1 по 2 строку, с 1 по 5 колонку)
ОбластьШапка.Область(1, 1, 2, 5).ЦветФона = WebЦвета.ЗеленыйЧай;

Проблема 3: Ограничения метода Выбрать() при фильтрации данных

Посмотрим на попытку автора отфильтровать сотрудников по филиалу работы:

Выборка = Справочники.Сотрудники.Выбрать(,,,"ФилиалРаботы");

Здесь происходит путаница между терминами «Отбор» (фильтрация) и «Сортировка» (упорядочивание).

Метод Выбрать() для справочников имеет строго определенную структуру параметров:

Выбрать(<Родитель>, <Владелец>, <Отбор>, <Порядок>)

Передав строку "ФилиалРаботы" четвертым параметром, разработчик попытался выполнить сортировку (упорядочивание) по этому полю. Чтобы наложить отбор (оставить только сотрудников определенного филиала), необходимо передать структуру в качестве третьего параметра.

Разберем, как написать отбор через Выбрать() правильно:


// Создаем структуру, где ключ — это имя реквизита в конфигураторе, а значение — ссылка на филиал
СтруктураОтбора = Новый Структура("ФилиалРаботы", ВыбранныйФилиал);

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

Важное примечание: в сообщении 17 автора была еще одна скрытая ошибка: попытка вызвать метод Заполнить() непосредственно у области (ОбластьПодвал.Заполнить(Выборка)). Этот метод доступен только у свойства Параметры этой области (ОбластьПодвал.Параметры.Заполнить(Выборка)).

Ограничения метода Выбрать(), о которых важно помнить

Даже если написать код отбора через Выбрать() синтаксически верно, велика вероятность столкнуться со следующими платформенными ограничениями:

  1. Необходимость индексирования. Использовать реквизит справочника в параметрах отбора или порядка метода Выбрать() можно только в том случае, если для этого реквизита в свойствах метаданных конфигурации установлено свойство «Индексировать» (или «Индексировать с дополнительным упорядочением»). Если индексация отключена, программа выдаст ошибку во время выполнения.
  2. Ограничение по количеству полей. Структура отбора в методе Выбрать() может содержать не более одного элемента. Сделать сложный отбор (например, одновременно по филиалу и статусу сотрудника) стандартным методом выборки объекта невозможно.

Рекомендуемое решение: Использование механизмов запросов

В современной практике разработки на платформе «1С:Предприятие» использование метода Выбрать() для сложных отборов и сортировок считается устаревшим и неэффективным подходом. Оптимальным решением является использование объекта Запрос.

Преимущества использования запросов:

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


// Инициализируем объект Запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Сотрудники.Ссылка КАК Ссылка,
    |	Сотрудники.Наименование КАК Наименование,
    |	Сотрудники.ФилиалРаботы КАК ФилиалРаботы
    |ИЗ
    |	Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |	Сотрудники.ФилиалРаботы = &ФилиалРаботы
    |УПОРЯДОЧИТЬ ПО
    |	Сотрудники.Наименование"; // Сортируем полученный список по алфавиту

// Передаем в параметр запроса ссылку на нужный филиал
Запрос.УстановитьПараметр("ФилиалРаботы", ВыбранныйФилиал);

// Выполняем запрос и получаем выборку результатов
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Заполняем параметры области макета данными из выборки запроса
    ОбластьПодвал.Параметры.Заполнить(Выборка);
    
    // Выводим готовую область в итоговый табличный документ
    ТабДок.Вывести(ОбластьПодвал);
КонецЦикла;

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

← На главную