Как решить проблему с блокировкой документа при открытии формы из расширения в 1С:ЗГУ 3.1?

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

При разработке расширений для типовых конфигураций, таких как ЗГУ 3.1 или ЗУП 3.1, программисты часто сталкиваются с неприятной особенностью платформы 1С:Предприятие 8.3. Речь идет о механизме пессимистической блокировки данных. Типичный сценарий: вы создаете в расширении дополнительную форму для расчетов (например, калькулятор премий), открываете её из основной формы документа, но платформа внезапно выдает ошибку: "Не удалось начать редактирование документа. Пользователь уже начал редактировать эти данные". При этом пользователем является тот же самый человек, который открыл документ.

В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем механизмы блокировок и рассмотрим несколько способов решения — от быстрого "костыля" до архитектурно правильного подхода.

Выясняем причину возникновения блокировки

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

Проблема заключается в том, что когда мы открываем форму из расширения и передаем в неё параметр Ключ (ссылку на объект), платформа воспринимает эту новую форму как самостоятельный инструмент редактирования. Поскольку основная форма уже удерживает блокировку, попытка формы из расширения также заблокировать этот же Ключ приводит к конфликту. Несмотря на то, что работает один и тот же пользователь в одном и том же сеансе, уникальные идентификаторы (UUID) у форм разные, и для системы это выглядит как попытка конкурентного доступа.

Рассмотрим типовой код открытия формы, который часто приводит к такой ошибке:


ОписаниеОповещенияОЗакрытии = Новый ОписаниеОповещения("ПослеЗакрытияМоейФормы", ЭтаФорма);
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", Объект.Ссылка); // Именно здесь зарыта проблема

ОткрытьФорму("Документ.Премия.Форма.А_ФормаПремирования", 
             ПараметрыФормы, 
             ЭтаФорма, 
             ,,, 
             ОписаниеОповещенияОЗакрытии);

Способ 1. Программная передача прав на редактирование

Если вы уже создали форму в расширении как форму документа, и вам нужно быстро решить проблему, можно воспользоваться методами управления блокировками. Суть метода заключается в том, чтобы при открытии формы расширения принудительно забрать "право владения" блокировкой у основной формы (владельца) и закрепить его за текущей формой.

Рассмотрим программную реализацию этого метода. В модуле формы расширения нам необходимо перехватить событие открытия:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Передаем уникальный идентификатор основной формы на сервер
    ПриОткрытииНаСервере(ЭтаФорма.ВладелецФормы.УникальныйИдентификатор);
КонецПроцедуры

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

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

Способ 2. Использование произвольной формы (Рекомендуемый)

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

Если ваша задача — создать "калькулятор" или вспомогательное окно для расчетов, правильнее будет сделать форму произвольной:

  1. В расширении создайте форму, не привязанную к конкретному документу (тип "Произвольная").
  2. Вместо передачи параметра Ключ, передавайте в форму структуру данных или просто ссылку через свой произвольный параметр.
  3. В произвольной форме платформа не будет автоматически вызывать ЗаблокироватьДанныеДляРедактирования.

В этом случае вы полностью контролируете процесс. Вы можете прочитать данные из документа, произвести расчеты и вернуть результат в основную форму через ОписаниеОповещенияОЗакрытии или напрямую обращаясь к ВладелецФормы.Объект. Для реализации подобного сценария подойдёт пример обработки для программного изменения и обновления формы документа.

Способ 3. Работа с данными формы без блокировки ссылки

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

В основной форме при вызове мы можем передать Объект как структуру. Тогда форма расширения будет работать с копией данных, находящихся в оперативной памяти клиента/сервера, не обращаясь к транзакционным механизмам базы данных до момента сохранения.

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

Важные рекомендации при работе в ЗГУ 3.1

Конфигурация Зарплата и кадры государственного учреждения построена на базе БСП и имеет сложную логику пересчетов. При изменении полей в форме документа часто запускаются фоновые процессы или обработчики ПриИзменении, которые сами по себе могут инициировать блокировки или длительные транзакции.

Поэтому всегда соблюдайте следующие правила:

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

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

← На главную