Почему очищаются программно добавленные колонки при записи документа в 1С и как это исправить?

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

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

Почему происходит очистка колонок? Анализ механизма платформы

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

Рассмотрим пошагово процесс записи на сервере:

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

Выясним причину: данные не «стираются» каким-то специальным кодом, они просто замещаются актуальным состоянием объекта из базы данных, в котором этих колонок не существует.

Решение 1: Восстановление данных через обработчики событий

Самый простой и эффективный способ борьбы с очисткой — повторное заполнение колонок сразу после того, как платформа обновила данные формы. Как было отмечено в обсуждении, нам необходимо задействовать два ключевых серверных обработчика формы.

Разберем, какие процедуры нам понадобятся:

  1. ПриЧтенииНаСервере — вызывается при открытии формы существующего документа. Здесь мы заполняем колонки первый раз.
  2. ПослеЗаписиНаСервере — вызывается после завершения транзакции записи. Именно здесь мы восстанавливаем данные, которые затерлись при обновлении формы из объекта.

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


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

Теперь подключим эту процедуру к стандартным обработчикам событий формы:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // Заполняем при открытии формы
    ЗаполнитьПрограммныеКолонкиНаСервере();
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    // Восстанавливаем данные после того, как платформа их очистила при записи
    ЗаполнитьПрограммныеКолонкиНаСервере();
КонецПроцедуры

Решение 2: Сохранение пользовательского ввода (через ВременноеХранилище)

Ситуация усложняется, если программные колонки предназначены не для вывода расчетных данных (как остатки), а для ручного ввода пользователем. В этом случае в ПослеЗаписиНаСервере нам нечего «вычислять», так как введенные пользователем данные уже пропали. Нам нужно их «спрятать» перед записью и «вернуть» после.

Рассмотрим алгоритм сохранения пользовательских данных:

  1. В обработчике ПередЗаписьюНаСервере выгружаем программные колонки во временную таблицу.
  2. Помещаем эту таблицу во ВременноеХранилище.
  3. В обработчике ПослеЗаписиНаСервере достаем таблицу из хранилища и сопоставляем данные со строками табличной части.

Проанализируем пример реализации этого метода:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Создаем таблицу для временного хранения данных программных колонок
    ТаблицаДанных = Объект.Товары.Выгрузить( , "НомерСтроки, МояПрограммнаяКолонка");
    
    // Сохраняем адрес в параметрах записи, чтобы передать его в ПослеЗаписиНаСервере
    ПараметрыЗаписи.Вставить("АдресХранилищаДанных", ПоместитьВоВременноеХранилище(ТаблицаДанных, ЭтаФорма.УникальныйИдентификатор));
    
КонецПроцедуры

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

Особенности трансформации данных: РеквизитФормыВЗначение

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

Если после модификации этого объекта вы вызываете ЗначениеВРеквизитФормы(Объект), то программные колонки в реквизите Объект на форме будут перезаписаны пустыми значениями из ОбъектЗначение. Поэтому, если вы используете эти методы, всегда вызывайте процедуру заполнения программных колонок сразу после ЗначениеВРеквизитФормы.

Резюме и рекомендации

Подведем итог. Программные колонки — это мощный инструмент интерфейса, но они требуют «ручного управления» их состоянием. Выясним основные правила работы с ними:

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

← На главную