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

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

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

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

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

Этот метод считается «золотым стандартом» в плане производительности динамических списков. Вместо того чтобы заставлять систему при каждом обновлении списка «обегать» все таблицы документов, мы будем хранить нужные нам ссылки в отдельном плоском регистре.

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

  1. Создадим Регистр сведений (например, ДанныеДляИнтеграции).
  2. В качестве измерений укажем ДокументОснование (тип нашего определяемого типа) и ДокументТМЦ.
  3. Чтобы данные в регистре всегда были актуальными, настроим Подписки на события. Нам понадобятся две подписки: ПриЗаписи и ПередУдалением для всех документов, входящих в состав определяемого типа.

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


Процедура СинхронизироватьДанныеВРегистре(Источник, Отказ) Экспорт
    
    // Сначала удалим старые записи по этому документу
    НаборЗаписей = РегистрыСведений.ДанныеДляИнтеграции.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.ДокументОснование.Установить(Источник.Ссылка);
    
    // Если документ помечается на удаление или удаляется, просто записываем пустой набор
    Если Источник.ПометкаУдаления Тогда
        НаборЗаписей.Записать();
        Возврат;
    КонецЕсли;
    
    // Если документ активен, заполняем набор данными из ТЧ
    Для Каждого СтрокаТЧ Из Источник.Товары Цикл
        НоваяЗапись = НаборЗаписей.Добавить();
        НоваяЗапись.ДокументОснование = Источник.Ссылка;
        НоваяЗапись.ДокументТМЦ = СтрокаТЧ.ДокументТМЦ;
    КонецЦикла;
    
    НаборЗаписей.Записать();
    
КонецПроцедуры

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

Способ 2. Использование механизма «Критерии отбора»

Если вы хотите избежать дублирования данных в регистрах, можно воспользоваться встроенным объектом метаданных — Критерием отбора. Этот объект специально создан для того, чтобы находить связи между различными документами.

Как мы это реализуем:

  1. Создадим новый объект КритерийОтбора.СвязанныеТМЦ.
  2. В свойстве «Тип» укажем тип данных, который мы ищем (например, ссылку на документ ТМЦ).
  3. Вкладка «Состав»: здесь выберем нужные табличные части всех документов, входящих в наш ОпределяемыйТип, и укажем колонку ДокументТМЦ.

Теперь мы можем использовать этот критерий в запросе динамического списка. Платформа сама сформирует оптимальный UNION ALL за нас:


ВЫБРАТЬ
    КритерийОтбора.СвязанныеТМЦ.Ссылка КАК ДокументОснование,
    КритерийОтбора.СвязанныеТМЦ.Значение КАК ДокументТМЦ
ИЗ
    КритерийОтбора.СвязанныеТМЦ(&ПараметрСсылка)

Важный нюанс: Критерии отбора отлично работают, когда нужно найти документы «по значению». Однако они накладывают определенные ограничения на использование основной таблицы в динамическом списке, что может сказаться на скорости при очень больших объемах данных.

Способ 3. Программное формирование текста запроса

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

Разберем, как проитерировать состав ОпределяемогоТипа и построить запрос с объединением всех таблиц:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ТекстЗапроса = "";
    МассивТипов = Метаданные.ОпределяемыеТипы.ДокументыДляИнтеграцииТМЦ.Тип.Типы();
    
    Для Каждого ТекущийТип Из МассивТипов Цикл
        
        МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТекущийТип);
        ИмяТаблицы = МетаданныеОбъекта.ПолноеИмя();
        
        // Предположим, ТЧ во всех документах называется одинаково "Товары"
        ТекстЗапроса = ТекстЗапроса + 
            "ВЫБРАТЬ ДокументТМЦ ИЗ " + ИмяТаблицы + ".Товары" + Символы.ПС;
        
        // Добавляем UNION ALL, если это не последний тип в массиве
        Если МассивТипов.Найти(ТекущийТип) <> МассивТипов.Количество() - 1 Тогда
            ТекстЗапроса = ТекстЗапроса + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
        КонецЕсли;
        
    КонецЦикла;
    
    Список.ТекстЗапроса = ТекстЗапроса;
    
КонецПроцедуры

Особенности этого подхода:

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

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

Если данных немного, а структура документов часто меняется, лучше рассмотреть программное построение запроса или Критерии отбора. Они избавят вас от необходимости хранить лишние данные в базе, обеспечивая при этом достаточную гибкость разработки.

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

← На главную