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