Как правильно изменить реквизиты объекта при сохранении из управляемой формы 1С?

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

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

В этой статье разберем, почему такой подход вызывает блокировки и ошибки транзакций, а также рассмотрим правильный способ модификации данных объекта в 1С.

Главная ошибка: повторный вызов ПолучитьОбъект() и Записать()

Рассмотрим распространенный ошибочный фрагмент кода, с которым часто сталкиваются начинающие разработчики:


// ОШИБОЧНЫЙ ПОДХОД в событии формы ПередЗаписьюНаСервере
СсылкаНаДокумент = Объект.Ссылка;
НашлиОбъект = СсылкаНаДокумент.ПолучитьОбъект();
НашлиОбъект.Заголовок = ИзмененноеНаименование;
НашлиОбъект.Записать(); // Ошибка!

Выясним причину, почему так делать категорически нельзя:

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

Правильное решение: использование параметра ТекущийОбъект

В событии управляемой формы ПередЗаписьюНаСервере платформа 1С автоматически передает параметр ТекущийОбъект (имеет тип СправочникОбъект или ДокументОбъект). Это и есть тот самый объект, который подготовлен платформой к записи в информационную базу.

Для изменения значений любых реквизитов достаточно внести изменения прямо в этот параметр. Никаких вызовов ПолучитьОбъект() или Записать() делать не нужно — платформа сама сохранит обновленные значения в текущей транзакции.

Проанализируем правильный пример доработки процедуры:


&НаСервере
Процедура ВнД_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Применяем изменения непосредственно к параметру ТекущийОбъект
    ТекущийОбъект.Заголовок = "Новое наименование";
    
    // Вызывать ТекущийОбъект.Записать() НЕ ТРЕБУЕТСЯ!
    // Платформа выполнит запись автоматически после завершения процедуры.

КонецПроцедуры

Корректный поиск дублей и проверка уникальности

Если задача заключается в поиске существующих документов с аналогичным наименованием и формировании уникального заголовка (например, с добавлением индекса -2, -3), необходимо правильно написать запрос с учетом следующих правил:

  1. Исключать из результатов текущий документ (используя условие Ссылка <> &ТекущаяСсылка), иначе при повторном сохранении объект найдет сам себя.
  2. Использовать оператор ПОДОБНО, чтобы учитывать уже измененные наименования с суффиксами.
  3. Сравнивать ссылки на справочники или перечисления, а не их строковые наименования, чтобы избежать ошибок при переименовании элементов пользователями в интерфейсе.

Рассмотрим итоговый рабочий пример формирования уникального заголовка в 1С:Документооборот:


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

КонецПроцедуры

Архитектурный совет

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

← На главную