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