При интеграции различных конфигураций 1С через COM-соединение разработчики часто сталкиваются со специфическими ошибками выполнения кода на стороне принимающей базы. Одной из самых распространенных и неочевидных проблем является аварийное завершение транзакции с ошибкой: «Попытка передачи с клиента на сервер мутабельного значения...».
В этой статье мы подробно разберем природу возникновения этой ошибки на примере интеграции баз «Управление производственным предприятием» (УПП) и «Камин», выясним технические причины такого поведения платформы 1С:Предприятие и рассмотрим несколько практических способов устранения проблемы.
Для начала проанализируем, что такое мутабельное значение в терминах 1С. Мутабельный объект — это сложный тип данных, состояние которого может динамически изменяться (например, ДокументОбъект, СправочникОбъект, ТаблицаЗначений). Платформа 1С запрещает передавать такие объекты между различными контекстами выполнения (например, с клиента на сервер) напрямую, так как они не могут быть однозначно сериализованы.
Когда мы подключаемся к базе данных через внешнее соединение с помощью объекта V83.COMConnector, платформа создает специальную сессию. Весь код, который выполняется в этой сессии, изначально выполняется в контексте «Внешнее соединение». С точки зрения платформы 1С, этот контекст во многом аналогичен клиентскому.
Рассмотрим по шагам, как разворачивается проблемная ситуация:
БазаПриемник.Документы.Прием.СоздатьДокумент().Записать() управление передается в модуль созданного документа базы-приемника, где срабатывает предопределенная процедура ПередЗаписью.ОбщегоНазначения.ПроверитьДатуФиксации(ЭтотОбъект, Отказ). В качестве параметра передается переменная ЭтотОбъект, которая имеет тип ДокументОбъект.Прием (мутабельное значение).ОбщегоНазначения в конфигураторе целевой базы выключен флаг «Внешнее соединение», но при этом включен флаг «Вызов сервера», платформа 1С не может выполнить метод модуля в текущем контексте. Она пытается перенаправить вызов на сервер приложений.ЭтотОбъект, система блокирует вызов и выбрасывает ошибку.---
Самый правильный и соответствующий стандартам разработки 1С способ решения проблемы — это настройка свойств самого общего модуля в конфигурации базы-приемника. Нам необходимо разрешить выполнение кода этого модуля непосредственно в контексте внешнего соединения, исключив необходимость обращаться к серверу приложений.
Выполним следующие шаги:
ОбщегоНазначения).Истина.Ложь (если логика модуля не требует обратного, но согласно стандартам 1С, для модулей, обрабатывающих мутабельные объекты, вызов сервера должен быть отключен).После включения флага «Внешнее соединение» код процедуры ПроверитьДатуФиксации начнет выполняться локально внутри сессии COM-соединения. Граница контекстов больше не пересекается, и передача мутабельного значения не вызывает ошибку.
---
Часто при программном создании документов из внешних систем нам не требуется выполнять интерактивные проверки (проверку даты запрета изменения, заполнение по умолчанию, контроль остатков и т.д.). Для этого в платформе предусмотрен механизм обмена данными.
Посмотрим на пример кода, который необходимо написать в базе-источнике:
// Создаем документ в базе-приемнике через COM
НовыйДокумент = COMБаза.Документы.Прием.СоздатьДокумент();
// Заполняем необходимые реквизиты
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = СсылкаНаОрганизацию;
// Устанавливаем признак загрузки данных
НовыйДокумент.ОбменДанными.Загрузка = Истина;
// Записываем документ
НовыйДокумент.Записать();
Важное предостережение: сам по себе флаг ОбменДанными.Загрузка = Истина не отключает выполнение кода в обработчиках событий автоматически. Разработчики конфигурации базы-приемника должны явным образом заложить эту логику в модуле документа.
Проанализируем структуру правильного обработчика события ПередЗаписью в модуле документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Первым делом проверяем, выполняется ли загрузка данных
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Весь остальной прикладной код и проверки
ОбщегоНазначения.ПроверитьДатуФиксации(ЭтотОбъект, Отказ);
КонецПроцедуры
Если разработчики целевой конфигурации не добавили условие Если ОбменДанными.Загрузка Тогда Возврат; в начало обработчика, то даже при установке этого флага в коде интеграции, система все равно попытается выполнить проверку даты фиксации и выдаст ошибку мутабельности. В таком случае потребуется вносить изменения в код базы-приемника.
---
Если у вас нет возможности изменять конфигурацию базы-приемника (например, она находится на замке и на поддержке поставщика), можно изменить способ интеграции.
Вместо легковесного V83.COMConnector мы можем инициализировать полноценное приложение через V83.Application:
// Инициализация полноценного приложения
COMБаза = Новый COMОбъект("V83.Application");
COMБаза.Connect("File=""C:\DB\Kamin"";Usr=""Администратор"";");
При использовании V83.Application запускается полноценный сеанс клиента 1С. В этом режиме контекст выполнения кода максимально приближен к обычной работе пользователя за компьютером. Платформа гораздо мягче относится к передаче объектов между модулями, что во многих случаях позволяет обойти ошибки мутабельности.
Однако помните о минусах этого подхода:
Application значительно ниже, чем у COMConnector.---
Мы подробно разобрали проблему передачи мутабельных значений при COM-интеграции. Наиболее надежным, быстрым и правильным решением является настройка свойств общих модулей базы-приемника (установка флага «Внешнее соединение»). В качестве альтернативы всегда стоит проверять корректность обработки флага ОбменДанными.Загрузка в процедурах записи документов, чтобы избегать ненужных проверок при программном обмене.