Как вывести данные из регистра сведений в форму списка или выбора справочника в 1С 8.3?

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

При проектировании интерфейсов в 1С часто возникает задача: отобразить в форме списка справочника какие-либо оперативные данные из связанного регистра сведений. Классический пример — справочник Оборудование, для которого в периодическом регистре сведений ОтветственныеЛица фиксируется история закрепления техники за сотрудниками. Нам необходимо вывести в общую форму списка справочника колонку «Текущий ответственный», чтобы пользователь сразу видел актуальную информацию без необходимости открывать карточку каждого элемента.

В этой статье мы подробно разберем два основных метода решения этой задачи на управляемых формах 1С v8.3: классический метод через изменение запроса динамического списка и современный высокопроизводительный метод через обработчик события ПриПолученииДанныхНаСервере. Мы проанализируем сильные и слабые стороны каждого подхода, разберем возможные подводные камни с производительностью и дублированием строк, а также приведем готовые примеры кода. Для расширения возможностей разработки и изучения альтернативных подходов можно использовать методы доработки динамических списков для добавления новых полей.

Способ 1. Использование произвольного запроса в динамическом списке (классический метод)

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

Разберем этот процесс по шагам:

  1. Откроем форму списка или форму выбора справочника в конфигураторе.
  2. Перейдем на вкладку «Реквизиты» и найдем основной реквизит формы — Список (имеет тип ДинамическийСписок).
  3. В панели свойств этого реквизита установим флаг «Произвольный запрос».
  4. Нажмем на гиперссылку «Открыть» рядом со свойством «Настройка списка». Перед нами откроется конструктор запроса.

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


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

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

Важные настройки, о которых нельзя забывать при использовании произвольного запроса:

Критические проблемы первого способа и пути их решения

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

Проблема 1. Дублирование строк в списке.
Если в регистре сведений ОтветственныеЛица помимо измерения Оборудование есть другие измерения (например, Организация или Подразделение), то виртуальная таблица СрезПоследних вернет срез для каждой уникальной комбинации всех измерений. Если для одного оборудования в регистре будут существовать записи по разным подразделениям, левое соединение размножит строки в списке справочника. Пользователь увидит один и тот же компьютер несколько раз в одной таблице, что вызовет путаницу.

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

Проблема 2. Падение производительности при работе с базой данных (особенно на СУБД PostgreSQL).
Использование левого соединения с виртуальной таблицей СрезПоследних в динамическом списке — одна из частых причин медленной работы интерфейса. СУБД строит неоптимальные планы запросов, пытаясь выполнить соединение таблиц «на лету» при каждой прокрутке списка или поиске по нему. На базах данных объемом в десятки тысяч элементов это может приводить к долгому зависанию формы.

Проблема 3. Работа с историческими данными (параметр Период).
По умолчанию срез последних берется на текущую дату. Если пользователю требуется увидеть состояние закрепления оборудования, например, на дату начала месяца, нам придется программно устанавливать параметр запроса. Сделать это можно в модуле формы, например, в событии ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Список.Параметры.УстановитьЗначениеПараметра("Период", ТекущаяДата());
КонецПроцедуры

Способ 2. Оптимальное решение через событие «ПриПолученииДанныхНаСервере»

Чтобы полностью исключить проблемы с производительностью СУБД при левых соединениях в динамических списках, рассмотрим современный альтернативный вариант, рекомендуемый стандартами разработки 1С. Этот подход основан на использовании события таблицы формы ПриПолученииДанныхНаСервере.

Суть метода заключается в следующем: запрос динамического списка остается максимально простым и легким (он выбирает только поля самого справочника Оборудование). Соединение с регистром сведений в основном запросе отсутствует. Когда платформа выводит на экран форму списка (обычно это всего 30-45 строк, видимых пользователю), срабатывает событие ПриПолученииДанныхНаСервере. В этот момент мы выполняем быстрый точечный запрос к регистру сведений только для этих 30-45 объектов и программно заполняем значения в добавленной нами колонке.

Разберем реализацию этого способа по шагам:

  1. Добавим в реквизит формы Список новое пользовательское поле (пустую колонку) с именем ТекущийПользователь (тип значения — СправочникСсылка.Пользователи). Это поле не связано с запросом динамического списка, оно будет заполняться программно.
  2. Вынесем это поле на форму в виде колонки таблицы. Если же требуется автоматизировать проверку информации в карточках без изменения интерфейса и программного кода, можно использовать платформу для создания программных роботов.
  3. Для таблицы формы (например, Список) создадим обработчик события ПриПолученииДанныхНаСервере.
  4. Напишем код серверного обработчика следующим образом:

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

Давайте проанализируем преимущества этого подхода:

Подведем итоги

Мы детально рассмотрели два способа интеграции данных из регистра сведений в форму списка или выбора справочника в среде 1С:Предприятие 8.3.

Первый способ (произвольный запрос динамического списка) отлично подходит для небольших и средних баз данных, где объем справочника и регистра сведений относительно невелик. Он прост в реализации и не требует написания сложного серверного кода. В таких случаях для разового наполнения справочников из других систем можно использовать инструмент для переноса данных между похожими конфигурациями 1С.

Второй способ (использование события ПриПолученииДанныхНаСервере) является золотым стандартом для высоконагруженных и крупных информационных систем. Он гарантирует высокую скорость отклика интерфейса при прокрутке списков, экономит ресурсы сервера баз данных и исключает проблемы с неоптимальными планами запросов в СУБД.

← На главную