При разработке алгоритмов выборки данных из справочников в платформе 1С 7.7 программисты нередко сталкиваются с ситуацией, когда метод поиска не находит нужные записи или цикл выборки обходит абсолютно все элементы вместо отфильтрованных. Разберем по шагам, почему возникают подобные ошибки и как правильно организовать поиск и выборку данных по значению реквизита.
Рассмотрим типичный фрагмент кода, в котором допущены сразу две распространенные ошибки:
СпрФТ = СоздатьОбъект("Справочник.ФильтрыТовары");
а = СпрФТ.НайтиПоРеквизиту("Номенклатура", Источник.Наименование, 1);
Если а = 1 Тогда
СпрФТ.ВыбратьЭлементы();
Пока СпрФТ.ПолучитьЭлемент() = 1 Цикл
Сообщить(СпрФТ.Номенклатура);
КонецЦикла;
КонецЕсли;
Выясним причину, почему такой алгоритм не работает ожидаемым образом:
Номенклатура в подчиненных справочниках или регистрах обычно имеет ссылочный тип Справочник.Номенклатура. Если передать в качестве второго параметра метода НайтиПоРеквизиту() строку с наименованием (Источник.Наименование), платформа попытается найти точное строковое совпадение. Так как тип реквизита — справочник, а тип поискового значения — строка, совпадение никогда не будет найдено.ВыбратьЭлементы(): Вызов ВыбратьЭлементы() начинает полный последовательный обход элементов всего справочника с начала, полностью сбрасывая текущую позицию, найденную методом НайтиПоРеквизиту(). Этот метод не выполняет фильтрацию по предыдущему поиску.Если перед нами стоит задача выбрать все элементы справочника, у которых значение реквизита равно заданному объекту, необходимо использовать специализированный метод ВыбратьЭлементыПоРеквизиту(). Сначала найдем искомую ссылку на номенклатуру, а затем выполним по ней отбор:
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
Если СпрНом.НайтиПоНаименованию(Источник.Наименование, 0, 1) = 1 Тогда
ИскомаяНоменклатура = СпрНом.ТекущийЭлемент();
СпрФТ = СоздатьОбъект("Справочник.ФильтрыТовары");
// Параметры: ИмяРеквизита, Значение, РежимИерархии (1 - с учетом иерархии), РежимГрупп (0 - элементы и группы)
СпрФТ.ВыбратьЭлементыПоРеквизиту("Номенклатура", ИскомаяНоменклатура, 1, 0);
Пока СпрФТ.ПолучитьЭлемент() = 1 Цикл
Сообщить("Найден элемент: " + СпрФТ.ТекущийЭлемент());
Сообщить("Фильтр: " + СпрФТ.Фильтр);
КонецЦикла;
Иначе
Сообщить("Номенклатура с наименованием " + Источник.Наименование + " не найдена.");
КонецЕсли;
Если требуется найти только один (первый попавшийся) элемент справочника, удовлетворяющий условию, используем метод НайтиПоРеквизиту() с корректной передачей ссылки на объект:
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
Если СпрНом.НайтиПоНаименованию(Источник.Наименование, 0, 1) = 1 Тогда
СсылкаНоменклатура = СпрНом.ТекущийЭлемент();
СпрФТ = СоздатьОбъект("Справочник.ФильтрыТовары");
Если СпрФТ.НайтиПоРеквизиту("Номенклатура", СсылкаНоменклатура, 1) = 1 Тогда
Сообщить("Найден элемент: " + СпрФТ.ТекущийЭлемент());
Сообщить("Фильтр: " + СпрФТ.Фильтр);
Иначе
Сообщить("Элемент в справочнике ФильтрыТовары не найден.");
КонецЕсли;
КонецЕсли;
Для корректной работы методов НайтиПоРеквизиту() и ВыбратьЭлементыПоРеквизиту() необходимо соблюдение правил конфигуратора:
Если у реквизита в конфигурации не установлен флаг «Сортировка» и менять метаданные нельзя, оптимальным решением является использование встроенного механизма запросов 1С 7.7:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ВыборкаПоРеквизиту)
|ТекущийЭлемент = Справочник.ФильтрыТовары.ТекущийЭлемент;
|Номенклатура = Справочник.ФильтрыТовары.Номенклатура;
|Фильтр = Справочник.ФильтрыТовары.Фильтр;
|Группировка ТекущийЭлемент без групп;
|Условие(Номенклатура = ИскомаяНоменклатура);
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Пока Запрос.Группировка(1) = 1 Цикл
Сообщить("Элемент: " + Запрос.ТекущийЭлемент);
Сообщить("Фильтр: " + Запрос.Фильтр);
КонецЦикла;
КонецЕсли;
Такой подход гарантирует корректную фильтрацию данных независимо от настроек индексации реквизита в конфигураторе.