Как быстро вывести реквизит связанного объекта в табличное поле обычных форм 1С 8?

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

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

Почему обращение через точку в ПриВыводеСтроки работает медленно?

Проанализируем типичный пример кода, вызывающий зависание интерфейса:


Процедура ТабличноеПолеПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    ОформлениеСтроки.Ячейки.Артикул.Текст = Формат(ДанныеСтроки.Номенклатура.Код, "ЧГ=");
КонецПроцедуры

Выясним причину падения производительности:

  1. Неявные запросы к базе данных: конструкция вида ДанныеСтроки.Номенклатура.Код при обращении к ссылочному реквизиту заставляет платформу считывать объект целиком из базы данных. Если в таблице отображается множество строк, на каждую строку выполняется отдельное обращение к серверу СУБД.
  2. Высокая частота вызова события: обработчик ПриВыводеСтроки срабатывает для каждой видимой строки при любых действиях пользователя — прокрутке списка, изменении размеров окна, смене фокуса ячейки или обновлении данных. В результате платформа генерирует лавину одиночных SQL-запросов.

Способ 1. Получение данных пачкой в событии ПриПолученииДанных

Наиболее правильным и платформенным решением для динамической подгрузки данных является использование события ПриПолученииДанных вместо ПриВыводеСтроки.

Разберем по шагам, как устроен этот механизм:

  1. Обработчик ПриПолученииДанных вызывается один раз для всей совокупности отображаемых на экране строк (параметр ОформленияСтрок), а не построчно.
  2. Мы собираем массив всех ссылок, отображаемых в данный момент на экране.
  3. Одним запросом с условием ГДЕ Ссылка В (&МассивСсылок) получаем все необходимые реквизиты.
  4. Заполняем соответствие или структуру полученными значениями и проставляем текст в ячейки переданных строк.

Посмотрим на пример реализации данного подхода:


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

Способ 2. Кэширование данных на уровне формы

Если пользователь часто листает таблицу туда и обратно, можно дополнительно сократить количество запросов, реализовав кэширование значений в переменной модуля формы типа Соответствие.

Рассмотрим, как это работает:

  1. В модуле формы объявляем переменную мКэшКодов.
  2. При открытии формы инициализируем ее: мКэшКодов = Новый Соответствие;.
  3. В обработчике ПриПолученииДанных проверяем наличие значения в кэше. Если значение найдено, сразу устанавливаем текст ячейки.
  4. В массив для запроса включаем только те ссылки, которых еще нет в кэше.
  5. Результаты выполненного запроса сохраняем в кэш для повторного использования.

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

Способ 3. Настройка свойств колонки для динамических списков

Если табличное поле отображает динамический список (например, СправочникСписок или ДокументСписок), программный код может вообще не потребоваться:

  1. Открываем свойства нужной колонки табличного поля.
  2. В свойстве Данные указываем путь через точку к реквизиту (например, Номенклатура.Код).

В этом случае платформа автоматически объединит таблицы в едином SQL-запросе списка, что обеспечит максимальную производительность без написания дополнительного программного кода.

Важные особенности и ограничения

Проанализируем нюансы, которые необходимо учитывать при разработке:

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