В процессе разработки на платформе 1С:Предприятие часто возникает задача программного получения списка объектов с определенными фильтрами. Одной из типичных задач является отбор номенклатуры по базовой единице измерения. Несмотря на кажущуюся простоту, начинающие разработчики часто сталкиваются с ошибками при использовании метода Выбрать() или при попытке сопоставить типы данных в запросах. В этой статье мы подробно разберем все способы решения этой задачи, проанализируем типичные ошибки и выясним, какой метод является наиболее эффективным.
Метод Выбрать() у менеджера справочника позволяет получить выборку элементов. Однако у него есть существенное ограничение: отбор (третий параметр метода) может осуществляться только по тем реквизитам, для которых в конфигураторе установлено свойство «Индексировать». Если вы попытаетесь передать в структуру отбора неиндексированное поле, система выдаст ошибку «Недопустимое значение параметра 3».
Рассмотрим пример кода, который изначально вызывал затруднения:
Отбор = Новый Структура("БазоваяЕдиницаИзмерения", Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("уп"));
Выборка = Справочники.Номенклатура.Выбрать(,, Отбор);
Пока Выборка.Следующий() Цикл
// Обработка элемента
КонецЦикла;
Почему этот код может не работать? Если в вашей конфигурации (например, в «Управление торговлей 10.3») реквизит БазоваяЕдиницаИзмерения не имеет индекса, программа выдаст исключение. Чтобы решить эту проблему, необходимо либо изменить свойства метаданных в конфигураторе, установив значение «Индексировать» для данного поля, либо воспользоваться механизмом запросов, который лишен этого ограничения.
Запросы — это наиболее гибкий и производительный способ получения данных в 1С. Рассмотрим ситуацию, когда нам нужно найти номенклатуру по строковому представлению единицы измерения. Важно помнить: БазоваяЕдиницаИзмерения — это ссылка, а не строка. Поэтому прямое сравнение с текстом "уп" в запросе не сработает корректно, если не обращаться к свойству Наименование.
Проанализируем правильный подход с использованием параметров запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.БазоваяЕдиницаИзмерения = &ВыбЕдиница";
// Находим ссылку на объект классификатора
СсылкаНаЕдиницу = Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("уп");
Запрос.УстановитьПараметр("ВыбЕдиница", СсылкаНаЕдиницу);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Действия с найденной номенклатурой
КонецЦикла;
Если же вам необходимо выполнить поиск по части наименования (например, условие «Содержит»), в запросах используется оператор ПОДОБНО (LIKE). Это позволяет находить элементы, даже если вы не знаете точного соответствия ссылки.
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.БазоваяЕдиницаИзмерения.Наименование ПОДОБНО ""%"" + &ТекстПоиска + ""%""";
Запрос.УстановитьПараметр("ТекстПоиска", "уп");
В обычных формах (ОФ) часто возникает задача: пользователь уже настроил сложные фильтры в списке номенклатуры на форме (используя стандартный диалог отбора), и программисту нужно получить именно те элементы, которые видит пользователь, чтобы обработать их в цикле. Вручную разбирать коллекцию Отбор у объекта СправочникСписок крайне трудозатратно, так как видов сравнения может быть много (в списке, в иерархии, содержит и т.д.).
Для этих целей идеально подходит Построитель отчета. Рассмотрим, как программно скопировать настройки отбора из экранной формы в объект построителя и получить результат:
ПостроительОтчета.Пример реализации данной логики:
// Предположим, СписокНоменклатуры — это реквизит формы с типом СправочникСписок.Номенклатура
ТекОтбор = ЭлементыФормы.СписокНоменклатуры.ОтборСтрок; // Или просто СписокНоменклатуры.Отбор
Построитель = Новый ПостроительОтчета;
// Инициализируем источник данных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(СписокНоменклатуры);
// Копируем фильтры
Для каждого ЭлементОтбора Из ТекОтбор Цикл
Если ЭлементОтбора.Использование Тогда
НовыйЭлемент = Построитель.Отбор.Добавить(ЭлементОтбора.ПутьКДанным, ЭлементОтбора.Имя);
НовыйЭлемент.ВидСравнения = ЭлементОтбора.ВидСравнения;
НовыйЭлемент.Значение = ЭлементОтбора.Значение;
НовыйЭлемент.ЗначениеС = ЭлементОтбора.ЗначениеС;
НовыйЭлемент.ЗначениеПо = ЭлементОтбора.ЗначениеПо;
НовыйЭлемент.Использование = Истина;
КонецЕсли;
КонецЦикла;
// Получаем результат в таблицу значений
Результат = Построитель.Результат;
ТаблицаЭлементов = Результат.Выгрузить();
Для каждого Строка Из ТаблицаЭлементов Цикл
// Работаем с отобранной номенклатурой
Сообщить(Строка.Ссылка);
КонецЦикла;
Этот метод является наиболее «элегантным» и профессиональным, так как он автоматически учитывает все сложности: иерархические отборы, сравнения по подстрокам и логику работы платформы 1С с динамическими списками.
При выполнении отборов важно не путать два разных реквизита, которые часто встречаются в типовых конфигурациях:
КлассификаторЕдиницИзмерения. Обычно это неизменяемая величина (шт, кг, литр).ЕдиницыИзмерения, который является подчиненным справочнику Номенклатура. В этом справочнике хранятся коэффициенты пересчета (например, «Коробка 10 шт»).Если ваша задача — найти всю номенклатуру, которая измеряется в «упаковках» (как в классификаторе), используйте первый вариант. Если же нужно найти номенклатуру, у которой конкретная единица хранения имеет определенные свойства — используйте второй вариант, обращаясь к подчиненному справочнику через запрос.
Подведем итог: для простого быстрого поиска по индексированному полю подходит метод Выбрать(). Для большинства рабочих задач и сложных условий оптимально использовать Запрос. А для синхронизации действий программы с тем, что пользователь выбрал на экране в списке, незаменимым инструментом становится ПостроительОтчета.