Разрешено ли использовать условие с методом Следующий() и проверкой данных в одной строке?

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

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

Ошибка 1: Ловушка логических вычислений в 1С

Рассмотрим ситуацию, когда разработчик пишет следующий код:


Если Выборка.Следующий() И Выборка.Номенклатура.Наименование <> "ххх" Тогда
    // Обработка данных
КонецЕсли;

Проанализируем механику работы этого условия. В многих современных языках программирования (таких как C#, Java или Python) реализованы так называемые короткие (ленивые) вычисления. Это значит, что если первая часть условия с оператором И возвращает Ложь, то вторая часть даже не вычисляется, так как результат всего выражения уже предопределен.

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

  1. Метод Выборка.Следующий() возвращает Ложь, так как данных больше нет.
  2. Платформа не останавливается и переходит к вычислению второй части: Выборка.Номенклатура.Наименование.
  3. Поскольку указатель выборки уже находится за пределами последней строки (так как метод вернул Ложь), обращение к полям выборки вызывает исключение (ошибку выполнения): "Чтение после конца выборки" или "Ошибка обращения к полю".

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


Пока Выборка.Следующий() Цикл
    Если Выборка.Наименование <> "ххх" Тогда
        // Безопасная обработка
    КонецЕсли;
КонецЦикла;

Ошибка 2: Проблема N+1 запроса (разъименование)

Проанализируем еще одну критическую деталь в исходном примере: обращение Выборка.Номенклатура.Наименование. В терминах платформы 1С это называется разыменованием ссылочного поля.

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

Рассмотрим, как правильно подготовить данные еще на этапе формирования запроса. Вместо фильтрации во встроенном языке, мы должны максимально использовать возможности SQL-сервера.

Решение 3: Оптимизация через текст запроса

Самый эффективный способ решить задачу — это перенести условие непосредственно в секцию ГДЕ текста запроса. Давайте посмотрим на пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Номенклатура,
    |   Номенклатура.Наименование КАК Наименование
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Наименование <> &ИсключаемоеНаименование";

Запрос.УстановитьПараметр("ИсключаемоеНаименование", "xxxxxxxxxx");
Выборка = Запрос.Выполнить().Выбрать();

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

Преимущества этого подхода:

  1. Минимизация трафика: СУБД передает на сервер приложений только те строки, которые действительно нужны.
  2. Использование индексов: Если поле проиндексировано, поиск по условию ГДЕ произойдет мгновенно, в то время как обход в цикле требует полного сканирования всех данных.
  3. Чистота кода: В цикле обхода выборки остается только бизнес-логика без лишних проверок.

Когда все же можно использовать фильтрацию в коде?

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

1. Явно выбирайте реквизиты. Если вам нужно наименование, добавьте его в секцию ВЫБРАТЬ запроса. Тогда обращение Выборка.Наименование не вызовет дополнительного обращения к серверу БД.

2. Используйте вложенные Если. Разделим проверку состояния выборки и проверку данных:


Пока Выборка.Следующий() Цикл
    // Условие внутри цикла безопасно, так как мы гарантированно стоим на записи
    Если Выборка.Наименование <> "ххх" Тогда
        // Обработка
    КонецЕсли;
КонецЦикла;

Подведем итоги

Мы проанализировали конструкцию Если Выборка.Следующий() И ... и выяснили, что она является ошибочной из-за отсутствия сокращенного вычисления логических выражений в 1С. Стремление к экономии строк кода в данном случае ведет к нестабильности системы.

Запомним основные правила качественного кода:

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

← На главную