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

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

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

Проблема производительности: эффект N+1 запроса

Рассмотрим ситуацию: у нас есть динамический список, в котором отображается 100 строк. Для каждой строки платформа вызывает обработчик получения представления. Если внутри кода происходит обращение к ссылочному реквизиту, платформа выполняет отдельный SQL-запрос к базе данных для получения этого значения. В итоге вместо одного запроса для получения списка мы получаем 1 + 100 запросов. Это значительно замедляет работу системы, особенно в «километровых» отчетах или при сортировке таблиц значений. Проанализируем основные методы решения этой проблемы.

Решение 1: Использование стандартного механизма ОбработкаПолученияПолейПредставления

Для того чтобы избежать лишних запросов, в платформе предусмотрен парный обработчик — ОбработкаПолученияПолейПредставления. Рассмотрим его работу по шагам. Этот метод позволяет «сказать» платформе, какие именно поля (включая поля через точку) ей нужно извлечь из базы данных одним общим запросом вместе с основной информацией об объекте.

В модуле менеджера объекта определим состав необходимых полей:


Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    Поля.Добавить("Номер");
    Поля.Добавить("Дата");
    Поля.Добавить("Ответственный.Наименование");
    Поля.Добавить("КонтактноеЛицо.Наименование");
    
КонецПроцедуры

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


Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ИмяОтветственного = "";
    Если Данные.Свойство("Ответственный_Наименование") Тогда
        ИмяОтветственного = Данные.Ответственный_Наименование;
    КонецЕсли;
    
    Представление = СтрШаблон("Документ №%1 от %2 (%3)", Данные.Номер, Формат(Данные.Дата, "ДЛФ=D"), ИмяОтветственного);
    
КонецПроцедуры

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

Решение 2: Денормализация (хранение представления в реквизите)

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

  1. Добавляем в объект (документ или справочник) реквизит ПредставлениеОбъекта с типом Строка.
  2. В модуле объекта в событии ПередЗаписью прописываем логику заполнения этого реквизита.
  3. В обработчике ОбработкаПолученияПредставления просто возвращаем значение этого реквизита.

Пример кода в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Формируем строку заранее
    ТекстОтветственного = ?(ЗначениеЗаполнено(Ответственный), Ответственный.Наименование, "Без ответственного");
    ПредставлениеОбъекта = СтрШаблон("%1 от %2 [%3]", Номер, Формат(Дата, "ДЛФ=D"), ТекстОтветственного);
    
КонецПроцедуры

Этот метод считается «базой» во многих типовых конфигурациях (например, так работает справочник ФизическиеЛица). Это исключает любые расчеты «на лету» и позволяет выполнять мгновенный поиск по строке представления.

Решение 3: Кэширование результатов

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

Рассмотрим пример создания оптимизированного метода в общем модуле:


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

Однако помните, что избыточное использование кэша на сервере может привести к повышенному потреблению оперативной памяти, поэтому кэшировать стоит только действительно «тяжелые» или часто запрашиваемые данные.

Актуальность данных и сложные случаи

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

Итоги и рекомендации

Подводя итог, можно сказать, что выбор метода зависит от конкретной задачи:

  1. Для большинства случаев оптимальным является использование ОбработкаПолученияПолейПредставления. Это «золотая середина» между скоростью и актуальностью.
  2. Если важна максимальная скорость поиска и сортировки в огромных списках — используйте отдельный реквизит НаименованиеСлужебное.
  3. Никогда не делайте прямых запросов Новый Запрос внутри ОбработкаПолученияПредставления без механизмов кэширования или предварительного отбора полей, так как это гарантированно приведет к деградации производительности всей системы.
← На главную