Разберем достаточно распространенную ситуацию при разработке на платформе 1С:Предприятие с использованием управляемых форм. Проблема заключается в том, что при открытии документа он не блокируется от изменений другими пользователями. В результате разные пользователи могут одновременно открыть один и тот же документ, отредактировать его и записать, тем самым затерев данные друг друга. Выясним причину такого поведения и рассмотрим подробнее, как правильно реализовать механизм блокировки.
Проанализируем типичный пример кода, который разработчики иногда помещают в обработчик ПриСозданииНаСервере в надежде заблокировать документ:
Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
Попытка
Объект.Ссылка.ПолучитьОбъект().Заблокировать();
Исключение
ШаблонСообщения = НСтр("ru = 'Документ редактируется другим пользователем.%1%2'");
ТекстСообщения = СтрШаблон(ШаблонСообщения, Символы.ПС, ОписаниеОшибки());
ВызватьИсключение ТекстСообщения;
КонецПопытки;
ЗаблокироватьДанныеФормыДляРедактирования();
КонецЕсли;
Посмотрим, что происходит в этом коде на самом деле и почему блокировка пропадает сразу после открытия формы.
Объект.Ссылка.ПолучитьОбъект().Заблокировать(). В управляемой форме реквизит Объект имеет тип ДанныеФормыСтруктура, а не ДокументОбъект. Вызывая ПолучитьОбъект(), мы создаем в оперативной памяти сервера совершенно новый, отдельный экземпляр объекта документа.ПриСозданииНаСервере завершается, платформа очищает память. Временный объект уничтожается сборщиком мусора, и, как следствие, установленная на него пессимистическая блокировка автоматически снимается. Для пользователя форма открывается, но реальный объект в базе данных остается свободным.Для управляемых форм платформой предусмотрен специальный метод: ЗаблокироватьДанныеФормыДляРедактирования(). Рассмотрим его особенности.
Этот метод не просто пытается установить блокировку, он возвращает булево значение. Если возвращается Истина, значит данные успешно заблокированы текущим сеансом. Если Ложь — объект уже заблокирован кем-то другим. В ошибочном коде выше результат выполнения этого метода просто игнорировался.
Блокировка, установленная этим методом, привязывается к расширению формы и сохраняется до тех пор, пока форма не будет закрыта, либо пока мы принудительно не вызовем метод РазблокироватьДанныеФормыДляРедактирования().
Разберем по шагам, как нужно переписать логику блокировки. Наиболее подходящим местом для таких проверок является обработчик ПриЧтенииНаСервере, так как он вызывается каждый раз при перечитывании данных из базы данных в форму.
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Пытаемся заблокировать данные формы
Если Не ЗаблокироватьДанныеФормыДляРедактирования() Тогда
// Если блокировка не удалась, запрещаем редактирование
ЭтаФорма.ТолькоПросмотр = Истина;
// Можно дополнительно сообщить пользователю
Сообщить("Документ открыт в режиме просмотра, так как редактируется другим пользователем.");
КонецЕсли;
КонецПроцедуры
Используя этот подход, мы гарантируем, что если другой пользователь уже занял объект, текущий пользователь увидит форму только для чтения и не сможет внести конфликтующие изменения.
Если код написан правильно, но "некоторые документы" всё равно иногда не блокируются или ведут себя странно, проанализируем дополнительные факторы:
РаботаСДиалогамиСервер. Часто в БСП применяется программный механизм через регистры сведений (например, запись информации о том, кто и когда открыл объект). Это позволяет не только блокировать документ, но и выводить пользователю информативное сообщение с указанием ФИО коллеги, который сейчас работает с документом.Подводя итог, откажитесь от использования ПолучитьОбъект() для целей блокировки в контексте формы. Опирайтесь на метод ЗаблокироватьДанныеФормыДляРедактирования(), обязательно проверяйте результат его выполнения и управляйте свойством ТолькоПросмотр. Это обеспечит стабильную работу системы и защитит данные от одновременной перезаписи.