Запись документа с открытой формой: как избежать ошибки «Объект изменен другим пользователем»

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

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

Выясняем причину: механизм оптимистической блокировки

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

Решение 1: Предварительная проверка блокировки в фоновом задании

Рассмотрим самый простой и надежный архитектурный подход. Чтобы не доводить ситуацию до конфликта версий, фоновое задание должно проверять, не занят ли объект пользователем в данный момент. Для этого используем механизм объектных блокировок, реализуя отслеживание результата фонового задания.

Проанализируем пример кода, позволяющий исполнить метод в фоновом задании:


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

Использование метода Заблокировать() позволяет фоновому заданию «отступить», если документ открыт у пользователя в режиме редактирования. Это предотвращает порчу данных и неожиданные ошибки на стороне клиента.

Решение 2: Использование обработчика ожидания для обновления формы

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

Разберем логику реализации:

  1. При открытии формы запускаем циклический опрос сервера.
  2. На сервере проверяем, изменилась ли версия данных документа.
  3. Если версия изменилась и пользователь не вносил свои правки, вызываем Прочитать().

Пример кода в модуле формы:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Запускаем проверку раз в 60 секунд
    ПодключитьОбработчикОжидания("ПроверитьОбновлениеДанных", 60);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОбновлениеДанных()
    Если НЕ ЭтаФорма.Модифицированность Тогда
        // Если пользователь ничего не менял, обновляем данные
        ОбновитьДанныеНаСервере();
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ОбновитьДанныеНаСервере()
    // Метод Прочитать() перечитает данные из БД и обновит элементы формы
    ЭтаФорма.Прочитать();
КонецПроцедуры

Важно помнить, что метод Прочитать() сбросит все незаписанные изменения пользователя (свойства элементов можно изучить через редактор форм в режиме предприятия), поэтому проверку свойства Модифицированность проводить обязательно.

Решение 3: Оповещение через Систему взаимодействия

Наиболее современный и технологичный способ — использование Системы взаимодействия. Этот метод позволяет избежать постоянных запросов к базе данных (как в случае с обработчиком ожидания) и переходить к обновлению только по сигналу от фонового задания.

Посмотрим, как это работает:

Этот подход минимизирует нагрузку на сервер и обеспечивает моментальную реакцию интерфейса на изменения в фоновом режиме.

Решение 4: Использование временных таблиц или регистров сведений (Merge)

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

Проанализируем преимущества этого метода:

  1. Отсутствие блокировок: Запись в регистр не блокирует сам документ.
  2. Актуальность: В форме документа мы можем отображать данные из регистра через динамический список или программное чтение при открытии/обновлении.
  3. Целостность: Документ остается «чистым», а все тяжелые расчеты хранятся рядом.

В этом случае в форме документа вместо обычного поля ввода для реквизита используется декорация-надпись или поле, связанное с данными регистра.

Решение 5: Ручное слияние данных (Advanced Merge)

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

Алгоритм действий следующий:

  1. Перед записью формы на сервере проверяем версию данных через ВерсияДанных.
  2. Если версии не совпадают, считываем актуальный объект из базы данных.
  3. Копируем изменения, внесенные пользователем в текущей форме, в этот новый объект.
  4. Записываем объект и обновляем форму.

Рассмотрим пример функции для сравнения версий:


&НаСервере
Функция ДанныеОбъектаИзменены()
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    Возврат ДокОбъект.Ссылка.ВерсияДанных <> ДокОбъект.ВерсияДанных;
КонецФункции

Если функция возвращает Истина, значит, фоновое задание уже внесло правки, и нам нужно либо предупредить пользователя, либо реализовать алгоритм программного объединения реквизитов.

Рекомендации по выбору решения

Выясним, какой метод лучше подходит в конкретных ситуациях:

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

← На главную