Перевод конфигурации на новые версии платформы «1С:Предприятие» и отключение режима совместимости — это важный шаг для оптимизации системы и использования современных механизмов разработки. Однако этот процесс нередко преподносит сюрпризы в виде неожиданного изменения поведения старого, годами работавшего кода. С одной из таких проблем разработчики часто сталкиваются при обновлении до платформы 8.3.15 и отключении режима совместимости с версией 8.3.13 и ниже.
В этой статье мы подробно разберем, почему возникает ошибка «Поле не найдено» при обращении к булевым измерениям в параметрах виртуальных таблиц, проанализируем причины этого поведения на уровне платформы и рассмотрим все возможные способы решения проблемы — от быстрого изменения кода (workarounds) до кардинального исправления ситуации.
Рассмотрим типичный сценарий. В конфигурации, где был отключен режим совместимости (или установлен в значение «Не использовать»), выполняется стандартный запрос к виртуальной таблице регистра накопления (например, РегистрНакопления.Продажи.Обороты). В параметрах этой таблицы (в секции отбора) используется измерение булева типа, которое напрямую сравнивается с логическим литералом ЛОЖЬ или ИСТИНА:
ВЫБРАТЬ Первые 1
ПродажиОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.Продажи.Обороты(, , , НеВключатьВСтатистику = ЛОЖЬ) КАК ПродажиОбороты
При выполнении этого запроса система неожиданно возвращает ошибку компиляции или выполнения следующего содержания:
Строка кода 5: {(5, 42)}: Поле не найдено "НеВключатьВСтатистику"
РегистрНакопления.Продажи.Обороты(, , , <<?>>НеВключатьВСтатистику = ЛОЖЬ) КАК ПродажиОбороты
При этом до отключения режима совместимости этот же запрос работал абсолютно корректно на протяжении многих лет. Более того, если добавить это поле в список выборки (секцию ВЫБРАТЬ) или убрать сравнение с литералом, ошибка пропадает. Выясним, почему так происходит.
Описанное поведение является следствием официально признанного бага платформы «1С:Предприятие 8.3». В официальном баг-трекере фирмы «1С» эта ошибка зарегистрирована под номером 000062053 (также в базах данных партнеров она фигурирует под кодами 10214823 и 20050800).
Причина кроется в оптимизации механизмов трансляции запросов, которая была реализована в ветке платформы 8.3.15 при отключенном режиме совместимости. Изменения коснулись разбора логических выражений внутри параметров виртуальных таблиц (таких как .Остатки(), .Обороты(), .СрезПоследних() и др.) при взаимодействии с СУБД. При парсинге условий вида ИмяИзмерения = ЛОЖЬ или ИмяИзмерения = ИСТИНА внутренний транслятор запросов 1С теряет метаданные соответствующего булева поля, ошибочно полагая, что данное поле отсутствует в структуре виртуальной таблицы, и прерывает выполнение запроса.
Данная ошибка воспроизводится на большинстве релизов ветки 8.3.15 (например, 8.3.15.1489, 8.3.15.1830, 8.3.15.1869).
В зависимости от возможностей администрирования вашей информационной системы и требований к производительности, вы можете выбрать один из нескольких вариантов решения проблемы. Проанализируем каждый из них по шагам.
Самый простой способ исправить код «здесь и сейчас» без изменения логики получения данных и без потери производительности — это отказаться от явного сравнения булева поля с литералами ЛОЖЬ и ИСТИНА. Платформа корректно транслирует логическое отрицание булевых переменных.
Давайте перепишем исходный запрос, применив оператор отрицания:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.Продажи.Обороты(, , , НЕ НеВключатьВСтатистику) КАК ПродажиОбороты
Если бы нам требовалось отобрать записи со значением ИСТИНА, мы бы просто указали имя поля без каких-либо дополнительных знаков равенства:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.Продажи.Обороты(, , , НеВключатьВСтатистику) КАК ПродажиОбороты
При таком написании транслятор запросов 1С не спотыкается на литералах, корректно сопоставляет поле с метаданными виртуальной таблицы и успешно выполняет запрос в СУБД.
Еще один надежный способ обойти ошибку транслятора — передавать значение отбора через параметры запроса. В этом случае типизация происходит на уровне СУБД при подстановке значений параметров, что предотвращает сбой парсера 1С.
Рассмотрим пример реализации на языке 1С:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Номенклатура КАК Номенклатура
|ИЗ
| РегистрНакопления.Продажи.Обороты(, , , НеВключатьВСтатистику = &ОтборПоСтатистике) КАК ПродажиОбороты";
// Передаем значение Ложь через параметр
Запрос.УстановитьПараметр("ОтборПоСтатистике", Ложь);
РезультатЗапроса = Запрос.Выполнить();
Этот метод так же эффективен, как и первый, и полностью сохраняет высокую скорость выполнения запроса, поскольку фильтрация по-прежнему происходит на уровне построения виртуальной таблицы.
Иногда разработчики переносят отбор из параметров виртуальной таблицы в общую секцию ГДЕ. Выглядит это следующим образом:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.Продажи.Обороты(, , , ) КАК ПродажиОбороты
ГДЕ
ПродажиОбороты.НеВключатьВСтатистику = ЛОЖЬ
Важное предупреждение: Данный метод крайне нежелателен, особенно для высоконагруженных баз данных и больших объемов информации в регистрах. Если перенести отбор в секцию ГДЕ, платформа СУБД сначала рассчитает виртуальную таблицу (обороты или остатки) по всем записям базы данных без ограничений, а уже затем начнет фильтровать полученный массив строк. Это приводит к колоссальным просадкам производительности, избыточному потреблению оперативной памяти и блокировкам таблиц.
Если добавить измерение НеВключатьВСтатистику в список выбираемых полей, ошибка действительно исчезнет, так как платформа будет вынуждена явно выгрузить метаданные этого поля в результирующий набор. Однако помните, что для виртуальных таблиц оборотов или остатков добавление нового измерения в секцию ВЫБРАТЬ приведет к изменению группировки результата запроса. Данные начнут разворачиваться и дублироваться в разрезе этого булева флага, что исказит итоговую выборку и сломает логику отчета.
Поскольку описанное поведение является явной ошибкой платформы, самым правильным и долгосрочным решением будет обновление технологической платформы «1С:Предприятие 8.3» на релиз, в котором этот баг был исправлен вендором.
Проанализируем версии платформы, в которых была устранена ошибка 000062053:
Мы проанализировали специфический сбой платформы 1С при работе с булевыми полями в параметрах виртуальных таблиц после отключения режима совместимости. Если ваша компания пока не готова к обновлению платформы на серверах, используйте безопасный обходной путь с заменой конструкции = ЛОЖЬ на оператор НЕ. Это позволит сохранить быстродействие системы и мгновенно возобновить работоспособность ваших алгоритмов.