Как исправить ошибку «Неоднозначное поле» при выполнении запросов в 1С:Документооборот?

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

При разработке и кастомизации конфигураций на платформе «1С:Предприятие» (в частности, такой функционально насыщенной, как «1С:Документооборот») программисты часто сталкиваются с неочевидным поведением запросов. Одной из типичных, но способных поставить в тупик проблем является ошибка компилятора запросов: «Неоднозначное поле [ИмяТаблицы].[ИмяПоля]».

В этой статье мы подробно разберем, почему возникает эта ошибка при выборе условий для реквизитов, как на это влияет механизм ограничения доступа на уровне записей (RLS — Row Level Security), почему ошибка может проявляться внезапно при изменении настроек прав или данных и как правильно составить запрос, чтобы раз и навсегда избежать подобных коллизий.

Анализ исходной ситуации и кода запроса

Рассмотрим реальный пример кода, который вызывает аварийное завершение работы запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |	ШаблоныВнутреннихДокументов.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ШаблоныВнутреннихДокументов КАК ШаблоныВнутреннихДокументов
    |ГДЕ
    |	ШаблоныВнутреннихДокументов.ВидДокумента = &ВидДокумента
    |	И НЕ ШаблоныВнутреннихДокументов.ПометкаУдаления";

Запрос.УстановитьПараметр("ВидДокумента", ВидДокумента);
Выборка = Запрос.Выполнить().Выбрать();

При выполнении этого кода система возвращает ошибку: «Неоднозначное поле "ШаблоныВнутреннихДокументов.ВидДокумента"». На первый взгляд, запрос написан абсолютно корректно: таблица-источник явно указана, поле существует, параметры передаются правильно. Выясним глубокую причину происходящего.

Технический механизм возникновения ошибки: Влияние RLS

Главным виновником возникновения ошибки является использование ключевого слова ВЫБРАТЬ РАЗРЕШЕННЫЕ в сочетании с некорректным именованием псевдонимов (алиасов) таблиц.

Когда платформа выполняет запрос с ключевым словом РАЗРЕШЕННЫЕ, она не просто транслирует его в СУБД. Платформа 1С динамически модифицирует текст запроса «на лету», добавляя в секцию ГДЕ дополнительные условия ограничения доступа (RLS), которые настроены для текущего пользователя в его ролях.

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

В исходном запросе разработчик допустил классическую ошибку:

Справочник.ШаблоныВнутреннихДокументов КАК ШаблоныВнутреннихДокументов

Псевдоним таблицы базы данных полностью совпадает с именем самого объекта метаданных. В процессе автоматической дописи RLS-ограничений транслятор запросов платформы подставляет внутренние подзапросы и условия. Из-за совпадения псевдонима и реального имени таблицы компилятор теряет контекст и не может определить, к какому именно источнику данных обращаться — к исходной таблице, объявленной в запросе, или к таблице, неявно добавленной механизмом RLS. Возникает коллизия имен, и платформа выбрасывает исключение «Неоднозначное поле».

Почему ошибка не проявлялась сразу?

Автор проблемы отметил важную деталь: «Ошибки не было, пока не добавила шаблон к другому типу документа». Это объясняется особенностями работы оптимизатора RLS в платформе «1С:Предприятие»:

  1. До изменения настроек: Если в системе был заведен всего один вид документа или у пользователя фактически были полные права на этот единственный вид, оптимизатор RLS мог упростить накладываемое условие (например, заменить его на истину ГДЕ ИСТИНА) или вовсе проигнорировать динамическую подстановку условий для этого конкретного объекта. Запрос отрабатывал успешно.
  2. После добавления шаблона к другому типу документа: Вступило в силу реальное разграничение прав доступа. Для пользователя активировалась сложная проверка прав по нескольким видам документов. Платформа была вынуждена внедрить в секцию ГДЕ развернутое и тяжелое RLS-ограничение, что мгновенно вскрыло скрытую коллизию псевдонимов в коде запроса.

Способы решения проблемы

Для устранения этой ошибки и предотвращения ее появления в будущем рассмотрим два основных решения.

Решение 1. Использование уникальных псевдонимов таблиц (Рекомендуемый способ)

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

Перепишем наш исходный запрос с использованием правильного псевдонима Шаблоны:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |	Шаблоны.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ШаблоныВнутреннихДокументов КАК Шаблоны
    |ГДЕ
    |	Шаблоны.ВидДокумента = &ВидДокумента
    |	И НЕ Шаблоны.ПометкаУдаления";

Запрос.УстановитьПараметр("ВидДокумента", ВидДокумента);
Выборка = Запрос.Выполнить().Выбрать();

В данном случае, даже если механизм RLS внедрит свои условия в тело запроса, компилятор четко определит, что обращение Шаблоны.ВидДокумента относится исключительно к нашей исходной таблице, именованной как Шаблоны. Ошибка «Неоднозначное поле» полностью исключена.

Решение 2. Использование привилегированного режима

Если этот запрос выполняется в рамках служебного алгоритма на сервере (например, при проведении документов, автоматическом заполнении реквизитов, в фоновом задании или при подписке на события), где проверка прав доступа конкретного пользователя не требуется или нецелесообразна, мы можем отказаться от использования конструкции РАЗРЕШЕННЫЕ.

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


УстановитьПривилегированныйРежим(Истина);

Запрос = Новый Запрос;
// Обратите внимание: слово РАЗРЕШЕННЫЕ убрано из текста запроса
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ШаблоныВнутреннихДокументов.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ШаблоныВнутреннихДокументов КАК ШаблоныВнутреннихДокументов
    |ГДЕ
    |	ШаблоныВнутреннихДокументов.ВидДокумента = &ВидДокумента
    |	И НЕ ШаблоныВнутреннихДокументов.ПометкаУдаления";

Запрос.УстановитьПараметр("ВидДокумента", ВидДокумента);
Выборка = Запрос.Выполнить().Выбрать();

УстановитьПривилегированныйРежим(Ложь);

При таком подходе платформа 1С полностью отключает проверку прав RLS для данного потока выполнения. Модификация текста запроса не происходит, условия RLS не дописываются, а значит, коллизия имен физически не может возникнуть. Кроме того, выполнение запроса в привилегированном режиме происходит быстрее, так как СУБД избавляется от необходимости обрабатывать дополнительные наложенные условия ограничения прав.

Правила проектирования запросов для предотвращения коллизий

Чтобы раз и навсегда обезопасить свои разработки от подобных проблем, придерживайтесь золотых правил написания запросов в 1С:

← На главную