Как использовать таблицу значений в качестве источника для динамического списка в 1С

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

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

Почему динамический список не работает с таблицей значений напрямую

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

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

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

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

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

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


// Очищаем старые данные текущего пользователя
НаборЗаписей = РегистрыСведений.СлужебныйБуферДанных.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Пользователь.Установить(ПараметрыСеанса.ТекущийПользователь);
НаборЗаписей.Записать();

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

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

Решение 2. Использование обычной таблицы формы с типизацией колонок

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

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


СверкаТЗ = Новый ТаблицаЗначений;
// Обязательно указываем типы данных для корректной работы поиска и отборов
КвалификаторыСтроки = Новый КвалификаторыСтроки(150);
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка",,,, КвалификаторыСтроки);
ОписаниеТипаКонтрагент = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");

СверкаТЗ.Колонки.Добавить("Контрагент", ОписаниеТипаКонтрагент);
СверкаТЗ.Колонки.Добавить("ИНН", ОписаниеТипаСтрока);

Для реализации отборов в обычной таблице на управляемой форме мы можем использовать:

Решение 3. Передача массива ссылок вместо всей таблицы

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

Проанализируем пример запроса в динамическом списке:


ВЫБРАТЬ
    ДокументПродажи.Ссылка,
    ДокументПродажи.Дата,
    ДокументПродажи.Номер
ИЗ
    Документ.РеализацияТоваровУслуг КАК ДокументПродажи
ГДЕ
    ДокументПродажи.Ссылка В (&МассивОтобранныхСсылок)

В коде формы (например, в процедуре ПриСозданииНаСервере) мы просто устанавливаем этот параметр:


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

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

Особенности использования временных таблиц (МВТ)

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

Помните: Динамический список эффективен только тогда, когда он работает с постоянными данными базы данных или простыми параметрами (массивы, примитивные типы, ссылки).

Резюме и рекомендации

Разберем краткие итоги нашего анализа:

  1. Не пытайтесь передать объект ТаблицаЗначений как параметр в запрос динамического списка. Это архитектурное ограничение платформы.
  2. Если нужно отобразить результат сложного расчета с возможностью полноценного поиска и отбора по миллионам записей — используйте регистр сведений как временный буфер.
  3. Если объем данных невелик (до 10-20 тысяч строк) — используйте обычную таблицу значений на форме. Не забудьте типизировать колонки через ОписаниеТипов.
  4. Если задача сводится к фильтрации существующих объектов базы данных — используйте динамический список с параметром типа Массив в условии ГДЕ Ссылка В (&Массив).

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

← На главную