Как исправить ошибку «Поле не найдено» при обращении к реквизитам составного типа в запросах 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Разбор ситуации: почему запрос перестал работать

Проанализируем классический сценарий. Предположим, у нас есть нетиповой регистр накопления ПродажиКомплектов. В его измерении Комплектация изначально был указан только один тип документа — ДокументСсылка.КомплектацияНоменклатуры. Запрос в СКД работал безупречно, обращаясь к ответственному лицу через точку от измерения:


РегистрНакопления.ПродажиКомплектов.Обороты(
    &НачалоПериода,
    &КонецПериода,
    Месяц,
    Комплектация.Ответственный В (&Сборщики)
) КАК ПродажиКомплектовОбороты

Проблема возникла сразу после того, как в состав типа измерения Комплектация был добавлен второй документ — например, ЗаказНаСборку. Для администратора (с полными правами) ничего не изменилось, но у рядовых пользователей отчет начал выдавать ошибку: «Поле не найдено "Комплектация.Ответственный"».

Выясним причину этого поведения. Когда поле имеет составной тип, платформа 1С при выполнении запроса пытается выполнить соединение (LEFT JOIN) со всеми физическими таблицами объектов, входящих в этот тип. Если у пользователя настроены ограничения доступа на уровне записей (RLS) хотя бы на одну из этих таблиц, механизм прав может заблокировать доступ к «разыменованию» (обращению через точку) для всего поля. В результате платформа «не видит» реквизит Ответственный, так как не может гарантировать безопасный доступ к данным всех таблиц составного типа.

Основное решение: Использование оператора ВЫРАЗИТЬ

Самый эффективный и правильный способ решения данной проблемы — явное приведение типа в параметрах виртуальной таблицы. Мы должны «подсказать» платформе, из какой именно таблицы нам нужно получить реквизит. Рассмотрим, как изменится наш запрос:


РегистрНакопления.ПродажиКомплектов.Обороты(
    &НачалоПериода,
    &КонецПериода,
    Месяц,
    (ВЫРАЗИТЬ(Комплектация КАК Документ.КомплектацияНоменклатуры)).Ответственный В (&Сборщики)
) КАК ПродажиКомплектовОбороты

Разберем по шагам, что дает нам использование ВЫРАЗИТЬ:

  1. Сужение области поиска: Платформа перестает пытаться соединиться с таблицей ЗаказНаСборку и другими возможными типами.
  2. Обход ограничений RLS: Поскольку запрос теперь жестко обращается только к одной таблице (КомплектацияНоменклатуры), на которую у пользователя есть права, механизм RLS отрабатывает штатно и поле становится «видимым».
  3. Оптимизация SQL-запроса: На уровне СУБД генерируется более простой запрос с меньшим количеством соединений, что положительно сказывается на производительности.

Влияние RLS и прав доступа

Важно понимать, что попытка просто добавить права на «Чтение» и «Просмотр» для нового типа документа (в нашем примере — ЗаказНаСборку) не всегда решает проблему. Если в роли прописаны сложные условия RLS (например, проверка по подразделению или организации), то даже при наличии прав на чтение, неявное обращение через точку в составном типе будет вызывать ошибку.

Проанализируем ситуацию, когда нам действительно нужно фильтровать по ответственному из обоих типов документов. В этом случае нам придется использовать конструкцию ВЫБОР или объединять условия через ИЛИ, также используя приведение типов:


(ВЫРАЗИТЬ(Комплектация КАК Документ.КомплектацияНоменклатуры)).Ответственный В (&Сборщики)
ИЛИ 
(ВЫРАЗИТЬ(Комплектация КАК Документ.ЗаказНаСборку)).Ответственный В (&Сборщики)

Почему нельзя просто перенести условие в ГДЕ

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


ВЫБРАТЬ *
ИЗ РегистрНакопления.ПродажиКомплектов.Обороты(&НачалоПериода, &КонецПериода, Месяц, ) КАК ПродажиКомплектовОбороты
ГДЕ ПродажиКомплектовОбороты.Комплектация.Ответственный В (&Сборщики)

Это плохая практика по следующим причинам:

Диагностика проблемы

Если вы столкнулись с подобной ошибкой, рекомендуем выполнить следующие действия для проверки:

  1. Запустите Консоль запросов под тем пользователем, у которого возникает ошибка.
  2. Попробуйте выполнить упрощенный запрос к регистру без параметров.
  3. Постепенно добавляйте условия в параметры виртуальной таблицы.
  4. Проверьте, не установлен ли флаг «Разрешенные» в тексте запроса. Хотя в СКД он добавляется автоматически, в ручных запросах его отсутствие при наличии RLS может приводить к ошибкам доступа.
  5. Убедитесь, что реквизит (в нашем случае Ответственный) существует во всех типах, входящих в составное поле, если вы не используете ВЫРАЗИТЬ. Хотя платформа иногда игнорирует отсутствие реквизита в части типов, в сочетании с RLS это гарантированно приводит к сбою.

Подводя итог, можно сказать, что использование ВЫРАЗИТЬ — это не просто способ исправления ошибки, а стандарт хорошего тона при написании запросов в 1С. Это делает ваш код более предсказуемым, производительным и устойчивым к изменениям в структуре метаданных.

← На главную