Почему пропадают данные из ДополнительныеСвойства при копировании документа и как это исправить?

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

При разработке в среде 1С:Предприятие 8.3 многие начинающие (и даже опытные) программисты сталкиваются с тем, что данные, помещенные в структуру ДополнительныеСвойства в обработчике ПриКопировании, бесследно исчезают к моменту записи документа. Давайте детально разберем, почему это происходит в управляемом приложении, и как правильно спроектировать механизм передачи служебной информации, чтобы она гарантированно "дожила" до момента фиксации данных в базе.

Анализируем причину: жизненный цикл объекта

Первым делом нам необходимо понять коренную причину проблемы. В управляемом интерфейсе 1С экземпляр объекта на сервере не существует постоянно. Процесс копирования и последующей записи документа в форме выглядит следующим образом:

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

Таким образом, попытка прочитать "старые" свойства в модуле объекта в процедуре ПередЗаписью или ПриЗаписи обречена на провал, если не использовать форму как промежуточное хранилище.

Решение проблемы: проброс данных через реквизит формы

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

Шаг 1. Добавим в расширение форму документа и создадим в ней новый реквизит, например, Расш_ОбъектКопирования (тип: ЛюбаяСсылка). Этот реквизит будет хранить информацию, пока форма открыта.

Шаг 2. В модуле формы перехватим момент создания документа на основании копии. Для этого идеально подходит процедура ПриСозданииНаСервере. Мы можем извлечь параметр ЗначениеКопирования, который платформа автоматически передает при копировании.


&НаСервере
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Проверяем, что это именно копирование, а не создание нового или открытие существующего
    Если Параметры.Свойство("ЗначениеКопирования") И ЗначениеЗаполнено(Параметры.ЗначениеКопирования) Тогда
        ЭтаФорма.Расш_ОбъектКопирования = Параметры.ЗначениеКопирования;
    КонецЕсли;
КонецПроцедуры

Шаг 3. Теперь нам нужно передать это значение обратно в объект, когда пользователь решит нажать кнопку "Записать". Лучшее место для этого — обработчик формы ПередЗаписьюНаСервере. В этот момент у нас есть прямой доступ к переменной ТекущийОбъект, которая представляет собой тот самый экземпляр, который будет записан в базу.


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

Шаг 4. Наконец, в модуле объекта (через расширение) мы можем спокойно обращаться к этим данным. Теперь они никуда не исчезнут, так как были вставлены в структуру ДополнительныеСвойства того же самого экземпляра объекта, который проходит через транзакцию записи.


&После("ПриЗаписи")
Процедура Расш_ПриЗаписи(Отказ)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    СсылкаНаОригинал = Неопределено;
    Если ДополнительныеСвойства.Свойство("ДокументКопирования", СсылкаНаОригинал) Тогда
        // Здесь выполняем логику копирования дополнительных сведений или регистров
        // Например: РегистрыСведений.ДополнительныеСведения.СкопироватьДляОбъекта(СсылкаНаОригинал, ЭтотОбъект.Ссылка);
    КонецЕсли;
КонецПроцедуры

Альтернативный вариант: программное копирование

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


НовыйОбъект = ИсходныйДокумент.Скопировать();
НовыйОбъект.ДополнительныеСвойства.Вставить("МойФлаг", Истина);
НовыйОбъект.Записать();

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

Тонкости использования ДополнительныеСвойства в расширениях

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

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

← На главную