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

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

При переходе с устаревших редакций конфигураций (например, с Бухгалтерии 1.2 на 2.0) разработчики часто сталкиваются с ситуацией, когда отлаженный годами код внезапно перестает работать в клиент-серверном режиме. Одной из самых коварных ошибок является: "Попытка передачи с клиента на сервер мутабельного значения 2-го параметра метода УстановитьУправляемуюБлокировку()". Рассмотрим подробнее, почему эта проблема не проявляется в файловых базах и как правильно адаптировать алгоритм для работы под SQL.

Разберем причину: разница между файловым и SQL-режимом

Первым делом проанализируем ситуацию: почему один и тот же код успешно выполняется на файловой копии, но «падает» в рабочей базе на SQL? Причина кроется в архитектуре платформы 1С:Предприятие.

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

В клиент-серверной версии (SQL) клиент и сервер — это разные процессы, которые могут находиться даже на разных физических серверах. Чтобы передать данные от клиента серверу, платформа должна выполнить их сериализацию (преобразовать в поток байтов). Мутабельные объекты (те, которые могут изменяться — например, ТаблицаЗначений, ДокументОбъект) не могут быть переданы таким образом, так как сервер не сможет поддерживать живую связь с объектом на клиенте. Платформа жестко блокирует такие попытки, чтобы избежать рассинхронизации данных.

Анализ ошибки в методе УстановитьУправляемуюБлокировку

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


СтруктураЗначенийБлокировки = Новый Структура("Период", Новый Диапазон(, ДокументОбъект.Дата));
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.Продажи");
ЭлементБлокировки.УстановитьЗначение("Период", СтруктураЗначенийБлокировки.Период);
Блокировка.Заблокировать();

На первый взгляд, объект Диапазон является сериализуемым. Однако проблема часто заключается в том, как именно передаются параметры. Если в конструктор Новый Диапазон передается реквизит мутабельного объекта ДокументОбъект.Дата, платформа может внутренне сохранять связь с этим объектом. При попытке передать такую структуру на сервер механизм проверки видит «хвост» мутабельного объекта и выдает ошибку.

Решение 1: Приведение к примитивным типам

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


// Извлекаем дату в локальную переменную, гарантируя примитивный тип
ЧистаяДата = Дата(ДокументОбъект.Дата); 

// Теперь создаем диапазон, используя чистую переменную
СтруктураЗначенийБлокировки = Новый Структура("Период", Новый Диапазон(, ЧистаяДата));

Этот подход гарантирует, что в структуру блокировки попадет сериализуемое значение, не обремененное ссылками на контекст ДокументОбъект.

Решение 2: Использование универсальных коллекций вместо Таблиц Значений

Часто ошибка возникает, если в параметры серверной процедуры передается ТаблицаЗначений. В клиент-серверном режиме ТаблицаЗначений является мутабельным типом и не может передаваться с клиента на сервер (за исключением некоторых случаев в Управляемых формах при использовании ДанныеФормыВЗначение, но мы рассматриваем Толстый клиент).

Выясним, чем можно заменить таблицу. Лучший вариант — использовать Массив Структур. Массивы и структуры сами по себе сериализуемы, если их содержимое состоит из простых типов. Посмотрим на пример преобразования:


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

// Теперь МассивПараметров можно безопасно передать на сервер
СерверныйМодуль.ОбработатьДанные(МассивПараметров);

Решение 3: Принудительная сериализация (метод "ЗначениеВСтрокуВнутр")

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

Посмотрим, как это реализовать:


// На стороне клиента упаковываем сложный объект в строку
ДиапазонСтрокой = ЗначениеВСтрокуВнутр(Новый Диапазон(, ДокументОбъект.Дата));

// Передаем эту строку в процедуру, а внутри процедуры разворачиваем обратно
НужныйДиапазон = ЗначениеИзСтрокиВнутр(ДиапазонСтрокой);

Важное замечание: Используйте этот метод с осторожностью. Метод ЗначениеВСтрокуВнутр создает текстовое представление объекта, которое может быть довольно объемным. Кроме того, этот подход скрывает архитектурные проблемы кода вместо того, чтобы их исправлять.

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

Чтобы избежать ошибок мутабельности при работе в SQL-базах, придерживайтесь следующих правил:

  1. Всегда очищайте типы: При передаче реквизитов документа или справочника в параметры процедур, преобразуйте их к простым типам (используйте функции Дата(), Число(), Строка()).
  2. Забывайте про Таблицы Значений на клиенте: Для передачи данных на сервер в Толстом клиенте используйте массивы и структуры.
  3. Контролируйте контекст: Если код выполняется в модуле объекта, помните, что ЭтотОбъект (или ДокументОбъект) всегда мутабелен. Любая ссылка на его данные внутри сложной структуры может сделать всю структуру мутабельной.
  4. Обновляйте платформу: В старых релизах (таких как 8.3.10) встречались ошибки платформенной сериализации объекта Диапазон. Современные версии 8.3.20+ работают гораздо стабильнее.

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

← На главную