При разработке управляемых форм в системе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью создания сложных выборок данных. Использование динамического списка с произвольным запросом — это мощный инструмент, однако он накладывает определенные ограничения и имеет свои нюансы. Одной из самых загадочных для новичков ошибок является сообщение: «Поле не найдено "DeletionMark"» (или его русскоязычный аналог «ПометкаУдаления», а также «Наименование» или «Predefined»).
В этой статье мы подробно разберем, почему возникает данная ошибка, как платформа 1С взаимодействует с текстом вашего запроса и какие шаги нужно предпринять, чтобы динамический список работал корректно и эффективно.
Для начала проанализируем ситуацию. Когда вы указываете у динамического списка свойство Основная таблица (например, Справочник.ФизическиеЛица), платформа берет на себя управление множеством стандартных функций: отображение стандартных картинок (пометка удаления, группы), работа с правами доступа (RLS), стандартные отборы и сортировки.
Для того чтобы отрисовать иконку строки, платформе необходимо знать значение поля ПометкаУдаления. Внутренние механизмы 1С используют англоязычные имена реквизитов, поэтому в тексте ошибки мы видим DeletionMark. Если ваш произвольный запрос построен с использованием временных таблиц (ВТ) или сложных соединений, итоговая выборка (самый последний запрос в пакете) может не содержать этого поля или содержать его под другим псевдонимом. В результате платформа «теряет» связь с объектом основной таблицы и выбрасывает исключение.
Важный нюанс: даже если вы добавили поле в первую временную таблицу, оно обязательно должно присутствовать и в финальном запросе пакета, который возвращает данные в список.
Рассмотрим ситуацию, описанную в теме. Автор пытался получить актуальные данные из регистра сведений «Кадровая история сотрудников» для каждого физического лица. Использование пакета запросов с временными таблицами в динамическом списке — это «тяжелое» решение, которое часто приводит к ошибкам сопоставления полей.
Проанализируем более простой и надежный подход. Вместо создания нескольких ВТ, попробуем использовать левое соединение со срезом последних в одном запросе. Это позволит платформе легче сопоставить поля основной таблицы.
Рассмотрим пример кода:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
СпрФизЛица.Ссылка КАК Ссылка,
СпрФизЛица.ПометкаУдаления КАК ПометкаУдаления,
СпрФизЛица.Наименование КАК Наименование,
СпрФизЛица.Код КАК Код,
КадроваяИстория.ВидСобытия КАК ВидСобытия,
КадроваяИстория.Организация КАК Организация
ИЗ
Справочник.ФизическиеЛица КАК СпрФизЛица
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АБС_КадроваяИсторияСотрудников.СрезПоследних(&Период, ) КАК КадроваяИстория
ПО СпрФизЛица.Ссылка = КадроваяИстория.ФизическоеЛицо
ГДЕ
НЕ СпрФизЛица.ПометкаУдаления
И ЕСТЬNULL(КадроваяИстория.ВидСобытия, ЗНАЧЕНИЕ(Перечисление.АБС_ВидыКадровыхСобытий.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Перечисление.АБС_ВидыКадровыхСобытий.Увольнение)
В данном примере мы сразу выбираем все необходимые поля из основной таблицы. Обратите внимание на поле ПометкаУдаления. Даже если вы не планируете выводить его в колонки списка на форме, оно должно присутствовать в выборке запроса, чтобы платформа могла корректно обрабатывать состояние строк.
Если специфика задачи все же требует использования временных таблиц (например, из-за сложной группировки данных), нам необходимо убедиться, что финальный запрос пакета «пробрасывает» все системные поля. Рассмотрим, как должен выглядеть исправленный пакетный запрос.
Шаг 1. В первой временной таблице мы отбираем нужные нам ссылки и периоды:
ВЫБРАТЬ
ФизическиеЛица.Ссылка КАК Ссылка,
МАКСИМУМ(КадроваяИстория.Период) КАК Период
ПОМЕТИТЬ ВТ_АктуальныеПериоды
ИЗ
Справочник.ФизическиеЛица КАК ФизическиеЛица
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АБС_КадроваяИсторияСотрудников КАК КадроваяИстория
ПО ФизическиеЛица.Ссылка = КадроваяИстория.ФизическоеЛицо
ГДЕ
НЕ ФизическиеЛица.ПометкаУдаления
СГРУППИРОВАТЬ ПО
ФизическиеЛица.Ссылка;
Шаг 2. В финальном запросе мы обязательно соединяемся обратно с физической таблицей справочника, чтобы получить актуальные значения всех стандартных реквизитов:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
СправочникФизическиеЛица.Ссылка КАК Ссылка,
СправочникФизическиеЛица.ПометкаУдаления КАК ПометкаУдаления,
СправочникФизическиеЛица.Наименование КАК Наименование,
СправочникФизическиеЛица.Код КАК Код,
СправочникФизическиеЛица.ЭтоГруппа КАК ЭтоГруппа,
СправочникФизическиеЛица.Предопределенный КАК Предопределенный
ИЗ
ВТ_АктуальныеПериоды КАК ВТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК СправочникФизическиеЛица
ПО ВТ.Ссылка = СправочникФизическиеЛица.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АБС_КадроваяИсторияСотрудников КАК КадроваяИстория
ПО ВТ.Ссылка = КадроваяИстория.ФизическоеЛицо
И ВТ.Период = КадроваяИстория.Период
ГДЕ
ЕСТЬNULL(КадроваяИстория.ВидСобытия, "") <> ЗНАЧЕНИЕ(Перечисление.АБС_ВидыКадровыхСобытий.Увольнение)
Проанализируем этот подход: здесь мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ с основной таблицей Справочник.ФизическиеЛица в самом конце. Это гарантирует, что все поля, такие как ПометкаУдаления, Наименование и Ссылка, будут получены напрямую из метаданных справочника, что исключает ошибку DeletionMark.
Если запрос выглядит верно, но ошибка сохраняется, нам следует проверить вкладку Настройки в окне редактирования запроса динамического списка:
Ссылка. Убедитесь, что там стоит флажок «Основное поле».Часто после исправления ошибки с полями программист сталкивается с другой проблемой: список открывается, но он пуст. Выясним, почему это происходит:
СрезПоследних(&Период), убедитесь, что параметр &Период передается в список. Это делается в коде формы: Список.Параметры.УстановитьЗначениеПараметра("Период", ТекущаяДата());.СрезПоследних с фильтром по организации, если у сотрудника есть записи в нескольких организациях, левое соединение может работать не так, как вы ожидаете. Всегда проверяйте результат запроса в консоли запросов перед переносом в динамический список.Работа с динамическими списками требует аккуратности при составлении текста запроса. Главное правило: финальный запрос пакета должен содержать все ключевые реквизиты основной таблицы. Использование конструкции ВЫБРАТЬ Спр.* (все поля таблицы) в финальном соединении часто является самым быстрым способом избавиться от ошибок типа «Поле не найдено».
Также рекомендуем придерживаться правила минимализма: динамический список — это не отчет. Его задача — быстро вывести данные для выбора или просмотра. Чем проще будет запрос (минимум временных таблиц, вложенных подзапросов и сложных условий в секции ГДЕ), тем стабильнее и быстрее будет работать ваша форма.