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

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

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

Выясним причину ограничения

Проанализируем ситуацию с точки зрения архитектуры платформы. ДинамическийСписок — это механизм, предназначенный для порционного (ленивого) считывания данных напрямую из СУБД (SQL). Когда мы описываем запрос в динамическом списке, платформа сама формирует SQL-запросы к базе данных, добавляя к ним условия отборов и сортировок, установленные пользователем. Таблица Значений, в свою очередь, является объектом, который живет исключительно в оперативной памяти сервера приложений 1С. Физического способа «соединить» таблицу в оперативной памяти и таблицы в базе данных SQL внутри одного запроса без предварительной записи в БД не существует. Именно поэтому ДинамическийСписок не может принять ValueTable как параметр.

Решение 1: Использование временного регистра сведений

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

  1. Создаем в конфигурации специальный Регистр Сведений (например, ВременныеДанныеДляСписков).
  2. В качестве ключевого измерения обязательно добавляем ИдентификаторСеанса (тип УникальныйИдентификатор) или Пользователь. Это необходимо, чтобы данные разных пользователей не перемешивались.
  3. Добавляем остальные необходимые поля, которые соответствуют колонкам вашей ТЗ (сориентироваться в доступных свойствах поможет Информер по метаданным — см. консоль запросов для анализа структуры метаданных).
  4. Перед открытием формы (или при обновлении данных) программно выгружаем данные из ТЗ в этот регистр.

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


// Генерируем уникальный ключ для текущего набора данных
ИдентификаторНабора = Новый УникальныйИдентификатор();

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

// Передаем идентификатор в параметр динамического списка
ДинамическийСписок.Параметры.УстановитьЗначениеПараметра("КлючСеанса", ИдентификаторНабора);

В тексте запроса динамического списка мы просто обращаемся к этому регистру:


ВЫБРАТЬ
    Регистр.Поле1,
    Регистр.Поле2
ИЗ
    РегистрСведений.ВременныеДанныеДляСписков КАК Регистр
ГДЕ
    Регистр.ИдентификаторСеанса = &КлючСеанса

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

Решение 2: Передача массива для фильтрации

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

Рассмотрим пример:


// Извлекаем массив ссылок из колонки ТЗ
МассивСсылок = МояТаблицаЗначений.ВыгрузитьКолонку("Ссылка");

// Устанавливаем параметр
Список.Параметры.УстановитьЗначениеПараметра("МассивФильтра", МассивСсылок);

В запросе динамического списка используем конструкцию В:


ВЫБРАТЬ
    Справочник.Наименование,
    Справочник.Код
ИЗ
    Справочник.Номенклатура КАК Справочник
ГДЕ
    Справочник.Ссылка В (&МассивФильтра)

Проанализируем ситуацию: этот метод работает очень быстро, если количество элементов в массиве не превышает нескольких тысяч. Если же в массиве будут десятки тысяч элементов, производительность СУБД может снизиться.

Решение 3: Динамическое конструирование текста запроса (Метод Литералов)

Существует экзотический способ, который подходит для небольших таблиц значений (до 10-20 строк). Мы можем программно изменить сам текст запроса динамического списка, вписав данные из таблицы значений прямо в тело запроса через конструкцию ВЫБРАТЬ... ОБЪЕДИНИТЬ ВСЕ.

Посмотрим, как это реализовать программно:


ТекстЗапроса = "";
Для Каждого СтрокаТЗ Из МояТаблицаЗначений Цикл
    Если ТекстЗапроса <> "" Тогда
        ТекстЗапроса = ТекстЗапроса + " ОБЪЕДИНИТЬ ВСЕ ";
    КонецЕсли;
    
    ТекстЗапроса = ТекстЗапроса + "ВЫБРАТЬ " + СтрокаТЗ.ЧисловоеПоле + " КАК Поле1, """ + СтрокаТЗ.ТекстовоеПоле + """ КАК Поле2";
КонецЦикла;

Список.ТекстЗапроса = ТекстЗапроса;

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

Решение 4: Почему не работает Менеджер Временных Таблиц (МВТ)?

Часто возникает вопрос: можно ли создать МенеджерВременныхТаблиц, наполнить его данными на сервере и передать в динамический список? Ответ: нет.

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

Альтернатива: Отказ от Динамического списка в пользу Таблицы Формы

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

Единственный минус — отсутствие «ленивой загрузки». Все данные из таблицы значений будут переданы на клиент сразу. Если в вашей таблице до 10 000 строк, использование обычной таблицы формы будет гораздо проще и эффективнее, чем попытки «подружить» ТЗ с динамическим списком.

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

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

  1. Для больших объемов данных — Регистр Сведений с ключом сеанса.
  2. Для фильтрации существующих справочников — Массив ссылок.
  3. Для простых задач отображения — Обычная Таблица Формы вместо динамического списка.

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

← На главную