Как программно проверить, что документ редактируется пользователем, и корректно его записать?

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

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

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

Проанализируем механику работы платформы при изменении объектов. В 1С одновременно действуют два ключевых механизма защиты целостности данных:

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

Способ 1. Проверка блокировки в обработке через метод объекта Заблокировать()

Рассмотрим, как учесть состояние объекта непосредственно в коде обработки. Перед тем как изменять реквизиты и вызывать метод записи объекта, необходимо явно попытаться наложить пессимистическую блокировку средствами встроенного языка с помощью метода Заблокировать().

Если пользователь уже начал вносить правки в интерактивной форме, вызов Заблокировать() вызовет исключительную ситуацию. Обернем этот вызов в конструкцию Попытка ... Исключение, чтобы обработка не прерывалась аварийно, а корректно отреагировала на занятость объекта.

Посмотрим на пример реализации:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

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

// Если блокировка успешна, выполняем модификацию и запись
ДокументОбъект.Комментарий = "Изменено обработкой";
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

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

Способ 2. Блокировка объекта сразу при открытии формы документа

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

Если логика бизнес-процесса требует зарезервировать документ за пользователем с первых секунд открытия формы, выполним принудительную блокировку на стороне формы:

  1. На клиенте в обработчике формы ПриОткрытии можно вызвать метод ЗаблокироватьДанныеФормыДляРедактирования().
  2. Либо на сервере при создании или чтении формы применить процедуру глобального контекста ЗаблокироватьДанныеДляРедактирования(), связав блокировку с уникальным идентификатором формы:

&НаСервере
Процедура ПриЧтенииСозданииНаСервере()
    // Блокируем данные с привязкой к идентификатору текущей формы
    ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, , ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры

При таком подходе блокировка сохраняется на все время существования формы и автоматически снимается сервером при ее закрытии. Сторонняя обработка при попытке вызова Заблокировать() сразу попадет в блок Исключение.

Способ 3. Пакетная обработка документов с пропуском занятых объектов

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


СписокПропущенных = Новый Массив;

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

Если СписокПропущенных.Количество() > 0 Тогда
    Сообщить("Часть документов не была обработана из-за блокировки пользователями.");
КонецЕсли;

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

← На главную