При доработке управляемых форм в 1С (включая работу через расширения конфигурации) разработчики часто сталкиваются с задачей изменения значения реквизитов объекта непосредственно перед его записью в базу данных. Распространенной ошибкой является попытка повторно получить объект из базы через ссылку (ПолучитьОбъект()) и вызвать метод Записать() прямо внутри события формы.
В этой статье разберем, почему такой подход вызывает блокировки и ошибки транзакций, а также рассмотрим правильный способ модификации данных объекта в 1С.
Рассмотрим распространенный ошибочный фрагмент кода, с которым часто сталкиваются начинающие разработчики:
// ОШИБОЧНЫЙ ПОДХОД в событии формы ПередЗаписьюНаСервере
СсылкаНаДокумент = Объект.Ссылка;
НашлиОбъект = СсылкаНаДокумент.ПолучитьОбъект();
НашлиОбъект.Заголовок = ИзмененноеНаименование;
НашлиОбъект.Записать(); // Ошибка!
Выясним причину, почему так делать категорически нельзя:
ПередЗаписьюНаСервере) платформа 1С уже начала процедуру записи и открыла транзакцию. Попытка вызвать ПолучитьОбъект() и выполняя для него Записать() приводит к блокировке данных или ошибке вида «Данные были изменены или удалены другим пользователем».Объект.Ссылка будет пустой. Вызов ПолучитьОбъект() для пустой ссылки возвращает Неопределено, что вызывает критическое завершение программы при обращении к свойствам.В событии управляемой формы ПередЗаписьюНаСервере платформа 1С автоматически передает параметр ТекущийОбъект (имеет тип СправочникОбъект или ДокументОбъект). Это и есть тот самый объект, который подготовлен платформой к записи в информационную базу.
Для изменения значений любых реквизитов достаточно внести изменения прямо в этот параметр. Никаких вызовов ПолучитьОбъект() или Записать() делать не нужно — платформа сама сохранит обновленные значения в текущей транзакции.
Проанализируем правильный пример доработки процедуры:
&НаСервере
Процедура ВнД_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Применяем изменения непосредственно к параметру ТекущийОбъект
ТекущийОбъект.Заголовок = "Новое наименование";
// Вызывать ТекущийОбъект.Записать() НЕ ТРЕБУЕТСЯ!
// Платформа выполнит запись автоматически после завершения процедуры.
КонецПроцедуры
Если задача заключается в поиске существующих документов с аналогичным наименованием и формировании уникального заголовка (например, с добавлением индекса -2, -3), необходимо правильно написать запрос с учетом следующих правил:
Ссылка <> &ТекущаяСсылка), иначе при повторном сохранении объект найдет сам себя.ПОДОБНО, чтобы учитывать уже измененные наименования с суффиксами.Рассмотрим итоговый рабочий пример формирования уникального заголовка в 1С:Документооборот:
&НаСервере
Процедура ВнД_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Сравниваем ссылку вида документа, а не строку
Если ТекущийОбъект.ВидДокумента = Справочники.ВидыВнутреннихДокументов.НайтиПоНаименованию("Задания смежному отделу") Тогда
ИсходныйЗаголовок = ТекущийОбъект.Заголовок;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| COUNT(ВнутренниеДокументы.Ссылка) КАК Количество
|ИЗ
| Справочник.ВнутренниеДокументы КАК ВнутренниеДокументы
|ГДЕ
| ВнутренниеДокументы.Заголовок ПОДОБНО &ШаблонЗаголовка
| И ВнутренниеДокументы.Ссылка <> &ТекущаяСсылка";
Запрос.УстановитьПараметр("ШаблонЗаголовка", ИсходныйЗаголовок + "%");
Запрос.УстановитьПараметр("ТекущаяСсылка", ТекущийОбъект.Ссылка);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() И Выборка.Количество > 0 Тогда
// Формируем новое наименование и присваиваем реквизиту ТекущийОбъект
НовыйЗаголовок = ИсходныйЗаголовок + "-" + Строка(Выборка.Количество + 1);
ТекущийОбъект.Заголовок = НовыйЗаголовок;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Обратите внимание: логика, завязанная исключительно на форму документа, не сработает при программном создании или перезаписи элементов (например, из фоновых заданий, через интеграцию или бизнес-процессы). Для обеспечения стопроцентной уникальности данных перенесите алгоритм проверки из модуля формы в модуль объекта (в событие ПередЗаписью) или создайте подписку на событие ПередЗаписью в расширении конфигурации.