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

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

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

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

Почему стандартный метод выгрузки динамического списка дает пустую ТЗ?

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


&НаСервере
Функция Получить_ТЗ_Из_ДинамическогоСписка()
    Схема = Элементы.СписокНоменклатуры.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.СписокНоменклатуры.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных();
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ТЗ = Новый ТаблицаЗначений;
    ПроцессорВывода.УстановитьОбъект(ТЗ); 
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Возврат ТЗ;
КонецФункции

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

  1. Таблица значений содержит колонки с индексами или системными полями, но в ней нет колонки со ссылкой на нужный объект (например, Номенклатуру).
  2. Таблица значений возвращается абсолютно пустой (0 строк), хотя на форме отображаются записи, соответствующие условиям отбора.

Выясним причины такого поведения платформы 1С:

---

Решение №1: Исправленный программный метод выгрузки в ТЗ через СКД

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

Рассмотрим детальный и рабочий пример кода:


&НаСервере
Функция ПолучитьОтобраннуюНоменклатуруИзСписка() Экспорт

    // 1. Получаем исполняемую схему и настройки динамического списка
    Схема = Элементы.СписокНоменклатуры.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.СписокНоменклатуры.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
    
    // 2. Очищаем выбранные поля и принудительно добавляем только Ссылку.
    // Это гарантирует наличие колонки в ТЗ, даже если она скрыта на форме.
    Настройки.Выбор.Элементы.Очистить();
    ВыбранноеПоле = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
    ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных("Ссылка");
    ВыбранноеПоле.Использование = Истина;
    
    // 3. Гарантируем структуру детальных записей, чтобы избежать пустой ТЗ
    Настройки.Структура.Очистить();
    ГруппаДетальныеЗаписи = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
    ГруппаДетальныеЗаписи.Использование = Истина;
    
    // Добавляем автовыбранные поля для детальной группировки
    АвтоПоле = ГруппаДетальныеЗаписи.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
    АвтоПоле.Использование = Истина;
    
    // 4. Компонуем макет для коллекции значений
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных();
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
    
    // 5. Инициализируем процессор компоновки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
    
    // 6. Выводим результат в Таблицу Значений
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Возврат ТаблицаРезультат;

КонецФункции

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

---

Решение №2: Высокопроизводительный метод через прямой SQL-запрос

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

Если ваша единственная цель — получить массив или таблицу ссылок для дальнейшего использования в собственном запросе (например, для заполнения документа), мы можем оптимизировать этот процесс. Мы заставим СКД только сгенерировать текст SQL-запроса и заполнить параметры, а сам запрос выполним через стандартный и быстрый объект Запрос.

Разберем этот продвинутый метод по шагам:


&НаСервере
Функция ПолучитьМассивСсылокБыстрымСпособом()

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

КонецФункции

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

---

Решение №3: Использование возможностей БСП (Библиотека Стандартных Подсистем)

Если вы работаете в современной типовой конфигурации 1С (например, 1С:Бухгалтерия предприятия 3.0, 1С:ERP или 1С:Управление торговлей 11), в вашей системе уже развернута Библиотека Стандартных Подсистем (БСП). Разработчики БСП создали ряд полезных общих модулей для работы с отборами компоновщика.

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

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


&НаСервере
Процедура АнализОтборовПользователя()

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

КонецПроцедуры

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

---

Важные предупреждения: Производительность и Полнотекстовый поиск

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

← На главную