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