Как программно записать новый документ из формы, чтобы избежать ошибки "Объект уже заблокирован"?

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

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

Анализ проблемы: почему возникает конфликт блокировок?

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


&НаКлиенте
Процедура ЗаписатьДокумент(Команда)
    ЗаписатьДокументНаСервере();
КонецПроцедуры

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

Ошибка "Объект уже заблокирован" появляется из-за параметра ПроверкаИсключительности, установленного в Истина. В данном случае параметр указывает системе, что перед записью нужно проверить, не заблокирован ли этот объект данных. И тут возникает парадокс: мы создаем новый документ, который еще никто не мог заблокировать. Так в чем же дело?

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

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

Решение: использование штатного механизма записи формы

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

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

Рассмотрим, как правильно модифицировать наш код.

  1. Создание обработчика на клиенте

    На клиенте мы вызываем серверную процедуру, которая выполнит запись. Важно отметить, что сам метод ЗаписатьВФорме() является серверным.

    
    &НаКлиенте
    Процедура МояКомандаЗаписи(Команда)
        // Вызываем серверный метод для записи
        ЗаписатьОбъектВФормеНаСервере();
    КонецПроцедуры
    
  2. Реализация записи на сервере

    В серверной процедуре мы вызываем метод ЗаписатьВФорме(). У него есть параметры, аналогичные обычному методу Записать().

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

    Важный момент: метод ЗаписатьВФорме() не требует передачи ему объекта. Он работает в контексте текущей формы автоматически.

Расширенный пример с проведением и закрытием формы

Давайте разберем более сложный сценарий, когда после записи документ нужно провести и закрыть форму.

Синтаксис метода:

ЗаписатьВФорме(<РежимЗаписи>, <ПараметрЗакрытия>)

Пример кода для проведения и закрытия:


&НаСервере
Процедура ЗаписатьПровестиИЗакрытьНаСервере()
    // Проверяем, можно ли провести документ
    Если НЕ Объект.ПроверкаЗаполнения() Тогда
        Возврат; 
    КонецЕсли;

    // Записываем в режиме проведения и указываем закрытие формы
    ПараметрЗакрытия = Новый ПараметрЗапускаКлиента("Закрыть");
    ЗаписатьВФорме(РежимЗаписиДокумента.Проведение, ПараметрЗакрытия);
КонецПроцедуры

В этом примере мы сначала выполняем стандартную проверку заполнения. Если проверка успешна, вызываем ЗаписатьВФорме() с нужными параметрами.

Подведем итог. Ключевое правило: если вам необходимо программно записать объект из его же открытой управляемой формы, всегда используйте серверный метод ЗаписатьВФорме(). Это безопасный и идеологически верный способ, который позволяет избежать конфликтов блокировок и корректно работает со всеми механизмами формы.

← На главную