Почему пропадают документы при добавлении дополнительных сведений в динамический список и как это исправить?

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

При доработке типовых конфигураций (например, «Управление торговлей», «Комплексная автоматизация» или «ERP») часто возникает задача вывести в форму списка документов значение дополнительного реквизита или сведения. Типичная ситуация: разработчик открывает запрос динамического списка, соединяет таблицу документов с регистром сведений РегистрСведений.ДополнительныеСведения и добавляет отбор по конкретному свойству в секцию ГДЕ. В результате часть документов — особенно те, у которых это сведение еще не заполнено, — бесследно исчезает из таблицы на форме.

Разберем подробно механику этой ошибки, выясним причину такого поведения запроса и рассмотрим правильные варианты реализации задачи.

Анализ проблемы: почему условие в секции ГДЕ отсекает строки

Проанализируем фрагмент запроса, который приводит к ошибке:


ИЗ
    Документ.ЗаказКлиента КАК ДокументЗаказКлиента
    ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
        ПО ДокументЗаказКлиента.Ссылка = ДополнительныеСведения.Объект
ГДЕ
    ДополнительныеСведения.Свойство.Наименование = "Заказ оплачен"

Даже если заменить ПОЛНОЕ СОЕДИНЕНИЕ на ЛЕВОЕ СОЕДИНЕНИЕ, проблема не решится. Выясним причину:

  1. В регистре ДополнительныеСведения физически хранятся только те записи, которые пользователь или интеграция уже записали в базу данных. Если у документа сведение никогда не заполнялось, в регистре нет соответствующей строки.
  2. При левом (или полном) соединении для документов без сведений все поля правой таблицы заполняются значением NULL.
  3. Секция ГДЕ применяется после выполнения соединений ко всей результирующей выборке. Когда платформа вычисляет выражение NULL = "Заказ оплачен", результат получается ложным (UNKNOWN / FALSE).
  4. В итоге строки документов, для которых сведение не задано, просто отфильтровываются. Наложение условия на поля правой таблицы превращает любое внешнее соединение во внутреннее.

Способ 1. Корректное использование левого соединения в запросе списка

Чтобы сохранить в динамическом списке все документы независимо от факта заполнения сведений, необходимо перенести условие фильтрации конкретного свойства непосредственно в секцию соединения ПО.

Посмотрим на пример правильной структуры запроса:


ВЫБРАТЬ
    ДокументЗаказКлиента.Ссылка КАК Ссылка,
    ДокументЗаказКлиента.Номер КАК Номер,
    ДокументЗаказКлиента.Дата КАК Дата,
    ВЫРАЗИТЬ(ЕСТЬNULL(ДополнительныеСведения.Значение, ЛОЖЬ) КАК Булево) КАК ЗаказОплачен
ИЗ
    Документ.ЗаказКлиента КАК ДокументЗаказКлиента
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
        ПО ДокументЗаказКлиента.Ссылка = ДополнительныеСведения.Объект
        И ДополнительныеСведения.Свойство = &СвойствоЗаказОплачен

Обратим внимание на ключевые правила построения этого запроса:

  1. Условие перенесено в блок ПО. В этом случае ограничение по свойству применяется только к правой таблице до момента объединения. Если запись с таким свойством не найдена, документ все равно останется в результирующем списке, а в поле значения придет NULL.
  2. Отказ от поиска по наименованию через точку. Конструкция ДополнительныеСведения.Свойство.Наименование = "Заказ оплачен" заставляет СУБД делать неявное дополнительное соединение с планом видов характеристик ДополнительныеРеквизитыИСведения и сравнивать строки, что существенно замедляет динамический список. Ссылку на свойство необходимо передавать через параметр &СвойствоЗаказОплачен (например, инициализируя его в событии формы ПриСозданииНаСервере с помощью функции ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию(...) или через предопределенный элемент).
  3. Обработка NULL и явное приведение типов. Поле Значение регистра имеет составной тип. Если реквизит логический, необработанный NULL вызовет отображение серого (третьего) состояния флажка в ячейке. Конструкция ВЫРАЗИТЬ(ЕСТЬNULL(ДополнительныеСведения.Значение, ЛОЖЬ) КАК Булево) гарантирует корректное отображение флажка (Да/Нет) на форме.

Как вывести несколько дополнительных сведений без дублирования строк

Если в список требуется добавить два или более сведений, частая ошибка — объединить условия через ИЛИ:


// ОШИБОЧНЫЙ ПОДХОД:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
    ПО ДокументЗаказКлиента.Ссылка = ДополнительныеСведения.Объект
    И (ДополнительныеСведения.Свойство = &Свойство1 ИЛИ ДополнительныеСведения.Свойство = &Свойство2)

При таком подходе для документа, у которого заполнены оба свойства, в выборке появятся две одинаковые строки с одной и той же ссылкой. Это сломает позиционирование динамического списка и приведет к ошибкам интерфейса. Для каждого свойства необходимо объявлять отдельное левое соединение с уникальным псевдонимом таблицы:


ВЫБРАТЬ
    ДокументЗаказКлиента.Ссылка КАК Ссылка,
    ДокументЗаказКлиента.Номер КАК Номер,
    ЕСТЬNULL(СведенияОплачен.Значение, ЛОЖЬ) КАК ЗаказОплачен,
    СведенияКурьер.Значение КАК Курьер
ИЗ
    Документ.ЗаказКлиента КАК ДокументЗаказКлиента
    
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК СведенияОплачен
        ПО (ДокументЗаказКлиента.Ссылка = СведенияОплачен.Объект)
        И (СведенияОплачен.Свойство = &СвойствоОплачен)
        
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК СведенияКурьер
        ПО (ДокументЗаказКлиента.Ссылка = СведенияКурьер.Объект)
        И (СведенияКурьер.Свойство = &СвойствоКурьер)

Способ 2. Штатный механизм характеристик БСП (без изменения запроса)

В типовых конфигурациях, построенных на «Библиотеке стандартных подсистем» (БСП), для большинства документов механизм характеристик подключен на уровне метаданных. Это позволяет вообще не переписывать текст запроса вручную.

  1. Убедимся, что в динамическом списке выбрано поле Ссылка.
  2. В режиме «1С:Предприятие» откроем форму списка, перейдем в меню Еще — Изменить форму (или «Настроить список»).
  3. Раскроем ветку поля Ссылка. Платформа отобразит доступные дополнительные реквизиты и сведения в виде вложенных полей.
  4. Добавим требуемое сведение как отдельную колонку. Платформа 1С самостоятельно сформирует оптимальный SQL-запрос выборки данных без риска задвоения строк или блокировки записей.

Важные технические нюансы работы с динамическим списком

При реализации ручного соединения таблиц в запросе динамического списка обязательно проконтролируем следующие параметры:

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