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

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

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

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

Почему метод Выбрать() выдает ошибку?

Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке использовать следующий код:


Отбор = Новый Структура("ПометкаУдаления"); 
Отбор.ПометкаУдаления = Ложь;
Выборка = Справочники[ИмяСправочника].Выбрать(,, Отбор);

Платформа генерирует ошибку "Недопустимое значение параметра (параметр номер '3')". Выясним причину, обратившись к синтакс-помощнику. Метод Выбрать() объекта СправочникМенеджер имеет жесткие ограничения на использование структуры отбора:

  1. В качестве полей для отбора могут задаваться только поля Код, Наименование и те реквизиты, для которых в Конфигураторе установлен признак Индексировать.
  2. Поле ПометкаУдаления является стандартным реквизитом, и оно по умолчанию не индексируется для целей метода Выбрать().
  3. Структура отбора в этом методе может содержать только один элемент.

Таким образом, использование Выбрать() для фильтрации «живых» записей невозможно. Рассмотрим правильные альтернативы.

Решение №1: Использование динамического запроса (рекомендуемый способ)

Запросы в 1С — это самый гибкий и производительный инструмент для получения данных. Если имя справочника хранится в переменной, мы можем сформировать текст запроса динамически. Проанализируем пример кода, который позволяет обойти ограничение:


// Предположим, переменная ИмяСправочника содержит "Контрагенты"
ТекстЗапроса = 
    "ВЫБРАТЬ
    |	Таблица.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.#ИмяСправочника КАК Таблица
    |ГДЕ
    |	НЕ Таблица.ПометкаУдаления";

// Заменяем маркер на реальное имя таблицы
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяСправочника", ИмяСправочника);

Запрос = Новый Запрос(ТекстЗапроса);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка объекта
    Сообщить(Выборка.Ссылка);
КонецЦикла;

Важный нюанс: Мы использовали СтрЗаменить() для подстановки имени справочника. Это необходимо, так как в языке запросов 1С нельзя передать имя таблицы (метаданных) через параметры запроса (через &Параметр). Параметры работают только для значений (дат, ссылок, чисел).

Решение №2: Универсальная функция для получения данных

Если в вашей конфигурации часто требуется выбирать данные из разных справочников по условию отсутствия пометки удаления, целесообразно оформить это в виде универсальной функции. Рассмотрим более продвинутый вариант с использованием функции СтрШаблон(), которая делает код более читаемым:


Функция ПолучитьВыборкуНеудаленных(ИмяСправочника) Экспорт
    
    ШаблонЗапроса = 
        "ВЫБРАТЬ
        |	Т.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.%1 КАК Т
        |ГДЕ
        |	Т.ПометкаУдаления = ЛОЖЬ";
    
    ТекстЗапроса = СтрШаблон(ШаблонЗапроса, ИмяСправочника);
    
    Запрос = Новый Запрос(ТекстЗапроса);
    Возврат Запрос.Выполнить().Выбрать();
    
КонецФункции

Такой подход позволяет минимизировать дублирование кода и легко поддерживать систему.

Решение №3: Фильтрация в цикле (для небольших справочников)

Иногда программисты выбирают путь «наименьшего сопротивления», просто перебирая все элементы и проверяя условие внутри цикла. Посмотрим на этот пример:


Выборка = Справочники[ИмяСправочника].Выбрать();
Пока Выборка.Следующий() Цикл
    Если Выборка.ПометкаУдаления Тогда
        Продолжить;
    КонецЕсли;
    
    // Работаем только с полезными данными
КонецЦикла;

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

Дополнительные советы и оптимизация

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

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

← На главную