Многие разработчики при переходе на новые релизы 1С:ERP Управление предприятием 2.5.12 (и аналогичные версии УТ 11.5 или КА 2.5) сталкиваются с неприятной ситуацией: код, который годами работал стабильно, внезапно начинает выдавать ошибку Поле не найдено. Особенно часто это проявляется в обработке Печать этикеток и ценников. Ситуация выглядит странно, так как синтаксис ВЫРАЗИТЬ(Поле КАК Справочник.Номенклатура).Реквизит кажется абсолютно корректным.
В этой статье мы подробно разберем, почему так происходит, какие изменения в платформе и типовых конфигурациях привели к этой проблеме, и рассмотрим два способа решения: «правильный» и «быстрый».
Рассмотрим типичный фрагмент кода, который вызывает сбой. Проблема возникает в момент помещения данных из переданной таблицы значений (параметр &Таблица) во временную таблицу в запросе:
ВЫБРАТЬ
ВЫРАЗИТЬ(ИсходныеДанные.Номенклатура КАК Справочник.Номенклатура) КАК Номенклатура,
ВЫРАЗИТЬ(ИсходныеДанные.Номенклатура КАК Справочник.Номенклатура).НаборУпаковок КАК НаборУпаковок
ПОМЕСТИТЬ ВТ_Данные
ИЗ
&Таблица КАК ИсходныеДанные
Система сообщает, что поле НаборУпаковок не найдено. Основная причина кроется в механизме работы платформы с временными таблицами, создаваемыми из внешних источников (Таблиц Значений). Когда мы обращаемся к реквизиту через точку (разыменование), платформа должна выполнить неявное соединение (Implicit Join) с таблицей справочника Номенклатура.
В последних версиях платформы (8.3.21 и выше), которые требуются для новых релизов ERP, контроль за выполнением запросов стал строже. Платформа больше не позволяет «пробрасывать» связи через точку для полей, которые еще не помещены в базу данных или не выбраны из физической таблицы. Так как &Таблица — это данные в памяти, находящиеся «вне» СУБД в момент разбора структуры, оптимизатор запроса блокирует попытку дотянуться до реквизитов справочника прямо в секции ПОМЕСТИТЬ.
Для того чтобы запрос работал стабильно на любых версиях платформы, мы должны отказаться от обращения к реквизитам через точку в момент первой загрузки данных. Нам необходимо разделить процесс на два этапа: загрузка ссылок и последующее соединение.
Шаг 1: Загрузка исходных данных во временную таблицу
На этом этапе мы выбираем из параметра &Таблица только сами ссылки и примитивные типы данных (количество, порядок и т.д.). Используем ВЫРАЗИТЬ только для типизации ссылочных полей, но не пытаемся получить их внутренние данные.
ВЫБРАТЬ
ВЫРАЗИТЬ(ИсходныеДанные.Номенклатура КАК Справочник.Номенклатура) КАК Номенклатура,
ВЫРАЗИТЬ(ИсходныеДанные.Характеристика КАК Справочник.ХарактеристикиНоменклатуры) КАК Характеристика,
ИсходныеДанные.Количество КАК Количество
ПОМЕСТИТЬ ВТ_Исходник
ИЗ
&Таблица КАК ИсходныеДанные
;
Шаг 2: Получение реквизитов через ЛЕВОЕ СОЕДИНЕНИЕ
Теперь, когда ссылки уже лежат в базе данных (во временной таблице), мы можем спокойно соединить их с физическими таблицами справочников. Рассмотрим этот пример подробнее:
ВЫБРАТЬ
ВТ_Исходник.Номенклатура КАК Номенклатура,
ВТ_Исходник.Характеристика КАК Характеристика,
СпрНоменклатура.НаборУпаковок КАК НаборУпаковок,
СпрНоменклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
ВТ_Исходник.Количество КАК Количество
ИЗ
ВТ_Исходник КАК ВТ_Исходник
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
ПО ВТ_Исходник.Номенклатура = СпрНоменклатура.Ссылка
Такой подход считается эталонным. Он не зависит от настроек «строгого режима» парсера запросов и гарантирует, что поле НаборУпаковок будет найдено, так как оно выбирается напрямую из таблицы справочника.
Бывают ситуации, когда запрос формируется динамически внутри сложных типовых механизмов (как в обработке печати ценников), и полностью переписывать структуру запроса слишком трудозатратно. В этом случае программисты часто прибегают к программной модификации текста запроса перед его выполнением.
Суть метода заключается в том, чтобы убрать обращение через точку из первого пакета запроса и перенести его во второй пакет, где данные уже выбраны из временной таблицы. Выясним причину эффективности этого метода: после того как данные помещены в ВТ_ИсходныеДанные, обращение ИсходныеДанные.Номенклатура.НаборУпаковок (через две точки) платформа уже может обработать, так как источник ИсходныеДанные уже является известной временной таблицей.
Посмотрим на пример кода, исправляющего текст запроса:
// Удаляем проблемные строки из секции ВЫБРАТЬ первого пакета
ТекстУдаления1 = "ВЫРАЗИТЬ(ИсходныеДанные.Номенклатура КАК Справочник.Номенклатура).НаборУпаковок КАК НаборУпаковок,";
Запрос.Текст = СтрЗаменить(Запрос.Текст, ТекстУдаления1, "");
ТекстУдаления2 = "ВЫРАЗИТЬ(ИсходныеДанные.Номенклатура КАК Справочник.Номенклатура).ЕдиницаИзмерения КАК ЕдиницаИзмерения,";
Запрос.Текст = СтрЗаменить(Запрос.Текст, ТекстУдаления2, "");
// В последующих пакетах заменяем обращение к полю ВТ на обращение через ссылку номенклатуры
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИсходныеДанные.НаборУпаковок", "ИсходныеДанные.Номенклатура.НаборУпаковок");
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИсходныеДанные.ЕдиницаИзмерения", "ИсходныеДанные.Номенклатура.ЕдиницаИзмерения");
Важное примечание: Использование этого метода требует осторожности. Если в вашей базе отключена функциональная опция использования упаковок, реквизит НаборУпаковок может стать недоступным на уровне метаданных, что вызовет аналогичную ошибку даже при правильном синтаксисе.
Подводя итоги нашего разбора, сформулируем основные правила работы с реквизитами из параметров-таблиц:
ПОМЕСТИТЬ.МассивТипов, но в самом запросе дополнительно используйте ВЫРАЗИТЬ для надежности.Артикул, Вес или ЕдиницаИзмерения), получайте их во втором пакете запроса через ЛЕВОЕ СОЕДИНЕНИЕ с основной таблицей соответствующего справочника.Версию совместимости платформы, что автоматически включает новые проверки синтаксиса запросов.Проанализировав ситуацию, мы видим, что проблема «Поле не найдено» — это не баг конфигурации, а следствие эволюции платформы 1С в сторону повышения производительности и строгости кода. Использование явных соединений делает ваш код более «чистым» и устойчивым к будущим обновлениям 1С:ERP.