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

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

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

Выясним причину возникновения ошибки

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

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

Решение 1: Вынос логики записи в серверный модуль (Метод «Моста»)

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

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

  1. Создайте общий модуль (например, РаботаСОбъектамиСервер) с установленными флажками «Сервер» и «Вызов сервера».
  2. В этом модуле опишите экспортную функцию для создания или обновления объекта.
  3. На клиенте (в модуле обычной формы) соберите данные из реквизитов формы в структуру.

Пример кода для серверного модуля:


Функция ЗаписатьКонтрагентаНаСервере(ДанныеЗаполнения) Экспорт
    
    // Если передана ссылка, получаем объект, если нет — создаем новый
    Если ДанныеЗаполнения.Свойство("Ссылка") И ЗначениеЗаполнено(ДанныеЗаполнения.Ссылка) Тогда
        НовыйОбъект = ДанныеЗаполнения.Ссылка.ПолучитьОбъект();
    Иначе
        НовыйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
    КонецЕсли;
    
    // Заполняем реквизиты из структуры
    ЗаполнитьЗначенияСвойств(НовыйОбъект, ДанныеЗаполнения);
    
    Попытка
        НовыйОбъект.Записать();
        Возврат НовыйОбъект.Ссылка;
    Исключение
        ЗаписьЖурналаРегистрации("Ошибка записи объекта", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение "Не удалось записать объект: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецФункции

Пример вызова этого метода из обычной формы:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    ДанныеДляЗаписи = Новый Структура;
    ДанныеДляЗаписи.Вставить("Наименование", ЭлементыФормы.Наименование.Значение);
    ДанныеДляЗаписи.Вставить("ИНН", ЭлементыФормы.ИНН.Значение);
    
    // Вызываем серверную функцию и получаем готовую ссылку
    СсылкаНаОбъект = РаботаСОбъектамиСервер.ЗаписатьКонтрагентаНаСервере(ДанныеДляЗаписи);
    
    Если Не СсылкаНаОбъект.Пустая() Тогда
        Сообщить("Объект успешно записан!");
    КонецЕсли;
    
КонецПроцедуры

Решение 2: Использование флага ОбменДанными.Загрузка

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

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


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

Это помогает, потому что стандартные обработчики БСП в самом начале содержат проверку: Если Источник.ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;. Таким образом, мутабельный объект Источник просто не передается дальше по стеку вызовов в проблемные процедуры.

Решение 3: Проблема мутабельных коллекций (ТЗ и Деревья значений)

Рассмотрим еще один нюанс, упомянутый в обсуждении. Часто ошибка возникает не только при записи объекта, но и при попытке передать на сервер ТаблицуЗначений или ДеревоЗначений из обычной формы. Эти типы также являются мутабельными.

Если вам нужно передать данные таблицы на сервер для обработки, выполните следующие действия:

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

Пример преобразования строки дерева значений в структуру перед отправкой на сервер:


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

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

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

Соблюдение этих принципов позволит создавать стабильные обработки, корректно работающие в любых режимах запуска 1С — поможет инструментарий для анализа метаданных и редактирования объектов.

← На главную