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

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

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

Почему нельзя передать Таблицу Значений напрямую?

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

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

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

Решение 1: Использование Внешних источников данных

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

Рассмотрим подробнее штатный механизм платформы — объект метаданных ВнешниеИсточникиДанных. Он позволяет подключаться к сторонним СУБД (PostgreSQL, MS SQL и др.) и работать с их таблицами так же, как с таблицами самой платформы.

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


ВЫБРАТЬ
    ВнешняяТаблица.Код,
    ВнешняяТаблица.Наименование,
    Регистр1С.Статус
ИЗ
    ВнешнийИсточникДанных.МояБаза.Таблица.Товары КАК ВнешняяТаблица
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СтатусыТоваров КАК Регистр1С
        ПО ВнешняяТаблица.Код = Регистр1С.КодТовара

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

Решение 2: Использование кэширующего Регистра Сведений

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

Разберем, как это реализовать, чтобы пользователи не мешали друг другу:

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

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

Решение 3: Заполнение колонок ПриПолученииДанныхНаСервере

Если мы хотим отобразить в динамическом списке данные, которые хранятся только в памяти, можно воспользоваться событием динамического списка ПриПолученииДанныхНаСервере.

Посмотрим на пример реализации. В динамическом списке мы выводим только ключевые поля (например, ссылку на справочник номенклатуры). В саму форму добавляем пустые пользовательские колонки. В модуле формы перехватываем событие получения данных:


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

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

Решение 4: Постраничный вывод с помощью обычной Таблицы Значений

Проанализируем ситуацию: действительно ли пользователю нужно видеть одновременно сотни тысяч записей? Чаще всего — нет. Если вам принципиально использовать именно ТЗ, откажитесь от объекта ДинамическийСписок в пользу обычного реквизита формы с типом ТаблицаЗначений.

Чтобы форма не зависала при открытии "огромной" таблицы, мы реализуем постраничный вывод:

  1. На сервере формируем полную таблицу данных и помещаем ее во ВременноеХранилище.
  2. На форме создаем кнопки переключения страниц ("Вперед", "Назад") и реквизит НомерСтраницы.
  3. На клиенте отображаем только ограниченный срез данных (например, по 500 строк).
  4. При переключении страницы обращаемся к серверу, читаем нужные строки из хранилища и загружаем их в реквизит формы для отображения.

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

← На главную