При организации обмена данными между различными конфигурациями 1С (например, между «Розницей» и «Управлением торговлей») разработчики часто прибегают к технологии COM-соединения. Это удобный механизм, позволяющий одной базе подключаться к другой и выполнять в ней программный код. Однако в процессе такой работы нередко возникает критическая ошибка: «Попытка передачи с клиента на сервер мутабельного значения». В результате документы могут не проводиться, а обмен — прерываться.
В этой статье мы подробно разберем природу мутабельных значений, выясним, почему они становятся камнем преткновения для COM-соединений, и рассмотрим пошаговые инструкции по решению этой проблемы.
Для начала давайте разберемся с терминологией. Мутабельные значения (от лат. mutabilis — изменчивый) — это объекты в 1С, состояние которых может быть изменено после их создания. В контексте платформы 1С это означает, что объект передается не как копия данных, а как ссылка на область памяти. Если одна сторона (клиент или одна база) изменит объект, эти изменения должны отразиться и на другой стороне.
Проблема заключается в том, что при использовании COM-соединения происходит процесс маршалинга — упаковки данных для передачи между разными процессами или даже серверами. Далеко не все типы данных 1С могут быть корректно «упакованы».
Проанализируем основные типы объектов, которые вызывают эту ошибку:
СправочникОбъект, ДокументОбъект, ПланВидовХарактеристикОбъект.ТаблицаЗначений, ДеревоЗначений, СписокЗначений (в определенных контекстах).ПостроительОтчета, Граница, МоментВремени, а также ОписаниеТипов.Когда вы пытаетесь передать, например, Структура, внутри которой лежит ТаблицаЗначений, через границу COM-соединения, система блокирует это действие, так как не может гарантировать синхронное изменение этого объекта в обеих базах.
Рассмотрим самый быстрый способ исправления ошибки, который часто помогает в типовых и слегка доработанных конфигурациях. Если процедура, которую вы вызываете через COM, находится в общем модуле, необходимо проверить его свойства.
Выполним следующие шаги:
Почему это помогает? Флаг Внешнее соединение позволяет коду модуля исполняться в контексте COM-сессии. Флаг Вызов сервера необходим, если COM-клиент обращается к методу, который должен отработать строго на стороне сервера. Это позволяет платформе более гибко управлять передачей контекста, хотя и не снимает ограничений на передачу «тяжелых» мутабельных объектов напрямую.
Разберем более надежный архитектурный подход. Если первый способ не помог, значит, внутри передаваемой структуры данных действительно находится «запрещенный» объект. Рассмотрим, как это можно исправить программно.
Вместо передачи самого объекта (например, документа), следует передавать только его идентификаторы. Посмотрим на пример кода, который вызывает ошибку:
// ОШИБОЧНЫЙ КОД
Процедура ВыполнитьОбмен(ОбъектДокумент)
// Попытка передать ДокументОбъект через COM вызовет ошибку
COMСоединение.ПринятьДанные(ОбъектДокумент);
КонецПроцедуры
А теперь проанализируем правильный подход. Мы передаем ссылку или строковое представление УИД (Уникального Идентификатора), которые являются примитивными или сериализуемыми типами:
// ПРАВИЛЬНЫЙ КОД
Процедура ВыполнитьОбмен(ОбъектДокумент)
// Передаем строку UUID
УИДСтрокой = Строка(ОбъектДокумент.Ссылка.УникальныйИдентификатор());
COMСоединение.ПринятьДанныеПоУИД(УИДСтрокой);
КонецПроцедуры
На стороне приемника (в COM-соединении) мы находим объект по этому УИД и работаем с ним локально. Это гарантирует отсутствие ошибок мутабельности.
Если вам необходимо передать не просто ссылку, а целую таблицу данных или сложную структуру, наилучшим выходом будет использование сериализации. Строка — это примитивный тип, который беспрепятственно проходит через любое COM-соединение.
Разберем по шагам процесс передачи ТаблицыЗначений через XML:
Шаг 1: На стороне отправителя
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ВашаТаблицаЗначений);
СтрокаДанных = ЗаписьXML.Закрыть();
// Передаем строку через COM
COMСоединение.ПринятьДанныеXML(СтрокаДанных);
Шаг 2: На стороне получателя (в общем модуле базы-приемника)
Функция ПринятьДанныеXML(ВходящаяСтрока) Экспорт
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ВходящаяСтрока);
ТЗ = СериализаторXDTO.ПрочитатьXML(ЧтениеXML, Тип("ТаблицаЗначений"));
// Теперь ТЗ — это локальная ТаблицаЗначений, с которой можно работать
// ...
КонецФункции
Этот метод считается «золотым стандартом» при разработке сложных интеграций, так как он полностью изолирует контексты двух баз друг от друга.
Часто ошибка возникает из-за того, что в общем модуле вызываются функции, предназначенные для работы с интерфейсом (например, открытие форм или предупреждения). В режиме COM-соединения (внешнего соединения) интерфейс отсутствует.
Выясним, как ограничить выполнение кода. Используем директивы препроцессора:
#Если НЕ ВнешнееСоединение Тогда
// Этот код не будет выполняться при подключении через COM
Предупреждение("Данные успешно переданы!");
#КонецЕсли
Это предотвратит попытки системы инициализировать клиентские объекты, которые по своей сути являются мутабельными и недоступными для COM.
Подведем итоги нашего исследования. Ошибка передачи мутабельного значения — это защитный механизм платформы 1С, предотвращающий нестабильную работу распределенных систем. Для ее устранения мы рекомендуем:
Объект передавайте Ссылка, а еще лучше — УникальныйИдентификатор.#Если.Применяя эти методы, вы обеспечите стабильную и быструю работу обмена данными между вашими конфигурациями 1С.