Как передать таблицу значений с сервера на клиент и избежать ошибки мутабельности?

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

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

Разберем понятие мутабельности в 1С

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

Напротив, иммутабельные (неизменяемые или просто сериализуемые) значения — это примитивные типы (Число, Строка, Дата, Булево) и ссылки (ДокументСсылка, СправочникСсылка). Также к передаваемым типам относятся Структура, Массив и Соответствие, но только при условии, что все элементы, внутри них содержащиеся, также являются передаваемыми.

Выясним причину ошибки в конкретной ситуации

Проанализируем ситуацию, описанную в теме. Разработчик пытается передать массив, полученный из таблицы значений, но система все равно выдает ошибку. Казалось бы, Массив — это разрешенный тип. Однако здесь вступают в силу два важных фактора:

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

Решение 1: Использование ключевого слова Знач (Val)

Самым простым и эффективным способом решения проблемы в большинстве случаев является использование ключевого слова Знач в заголовке функции или процедуры. Это указывает платформе, что параметр передается «по значению». В этом случае создается локальная копия объекта на сервере, и система не пытается вернуть его измененное состояние обратно на клиент по завершении вызова.

Рассмотрим пример кода, который помог автору темы:


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

Добавление Знач к параметру Объект (который часто является мутабельным ДокументОбъект) позволяет избежать ошибки, так как платформа перестает пытаться синхронизировать этот сложный объект между слоями системы.

Решение 2: Очистка коллекции от мутабельных типов

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

Посмотрим на пример подготовки данных для передачи:


// На сервере
ТаблицаДляПередачи = НаборДвижений.Выгрузить();
// Оставляем только нужные колонки с простыми типами или ссылками
ТаблицаДляПередачи.Свернуть("Период, Регистратор, Сумма", ""); 

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

Возврат МассивРезультат;

Решение 3: Использование временного хранилища

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

Рассмотрим алгоритм действий по шагам:

  1. На сервере помещаем таблицу значений во временное хранилище.
  2. Возвращаем на клиент только адрес (строку) этого хранилища.
  3. На клиенте (если это толстый клиент) мы можем извлечь данные или передать этот адрес в другой серверный вызов.

// На сервере
АдресХранилища = ПоместитьВоВременноеХранилище(МояТаблицаЗначений, Новый УникальныйИдентификатор);
Возврат АдресХранилища;

// На клиенте
Таблица = ПолучитьИзВременногоХранилища(АдресХранилища);

Важный нюанс: В тонком клиенте ПолучитьИзВременногоХранилища вернет таблицу значений только в том случае, если вызов происходит на сервере. На самом клиенте (в тонком режиме) ТЗ недоступна как тип объекта. Но для УПП 1.3 и толстого клиента этот метод работает превосходно.

Почему ТЗ нельзя передавать напрямую, а массив — можно?

Как отмечалось в обсуждении, ТаблицаЗначений в обычных формах несет в себе не только данные, но и информацию о визуальном оформлении, которая не подлежит сериализации (переводу в последовательность байтов для передачи по сети). Массив же является более простым контейнером, предназначенным исключительно для хранения данных. Именно поэтому преобразование ТЗ в массив структур является «классическим» способом обмена данными в 1С.

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

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

← На главную