Как сохранить табличную часть документа при открытии и передать данные в другую процедуру для сравнения?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает специфическая задача: необходимо зафиксировать состояние табличной части (ТЧ) документа в момент его открытия, чтобы позже, например, при записи или закрытии формы, сравнить эти данные с измененными. Это особенно актуально при создании расширений, когда сторонняя обработка или стандартные механизмы могут программно менять данные, и нам нужно отследить эти изменения для выполнения дополнительной логики или проверок.

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

Способ 1. Использование реквизита формы типа ТаблицаЗначений

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

Проанализируем алгоритм действий:

  1. В расширении формы документа создаем новый реквизит (например, с именем КопияТЧ) и назначаем ему тип ТаблицаЗначений.
  2. Добавляем в эту таблицу колонки, идентичные тем, что есть в целевой ТЧ документа.
  3. В серверном событии ПриСозданииНаСервере или ПриЧтенииНаСервере выполняем выгрузку данных.

Рассмотрим пример кода:


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

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

Преимущество: Данные всегда под рукой на сервере в типизированном виде, их удобно сравнивать и обрабатывать.

Способ 2. Помещение данных во временное хранилище

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

Разберем, как это работает по шагам:

  1. Выгружаем ТЧ в таблицу значений или массив структур.
  2. Помещаем объект во временное хранилище, используя УникальныйИдентификатор формы.
  3. Сохраняем адрес хранилища в строковом реквизите формы, чтобы потом по нему найти данные.

Пример реализации:


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

&НаСервере
Процедура СравнитьДанныеИзХранилища()
    // Проверяем, есть ли адрес
    Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда
        СтараяТЧ = ПолучитьИзВременногоХранилища(АдресХранилища);
        
        // Логика сравнения...
    КонецЕсли;
КонецПроцедуры

Важный момент: Переменная АдресХранилища должна быть реквизитом формы (тип Строка), чтобы она сохраняла свое значение между серверными вызовами.

Способ 3. Использование массива структур

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

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

Рассмотрим пример формирования такого массива:


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

Этот массив можно хранить в обычном реквизите формы с типом Произвольный. Он будет доступен в любой процедуре модуля формы.

Способ 4. Сериализация в JSON (продвинутый метод)

Для оптимизации передачи данных между клиентом и сервером можно использовать JSON-сериализацию. Мы превращаем всю таблицу значений в одну длинную строку. Это особенно полезно, если вы хотите минимизировать нагрузку на контекст формы.

Рассмотрим, как это реализовать:

В момент открытия мы преобразуем ТЧ в JSON и сохраняем в скрытый реквизит формы. При записи документа мы снова преобразуем текущую ТЧ в JSON и просто сравниваем две строки. Если строки идентичны — значит, ничего не менялось. Это избавляет нас от необходимости писать сложные циклы сравнения по каждой колонке.

Особенности работы в расширениях

Работая с расширениями, важно помнить, что мы часто перехватываем события через аннотации &Перед, &После или &Вместо. Если наша задача — поймать момент, когда сторонняя обработка изменила документ и записала его, лучше всего использовать Подписку на событие или расширение метода ПередЗаписьюНаСервере.

Выясним причину, почему переменные модуля (объявленные через Перем) — это не всегда хорошее решение. В управляемом приложении серверный контекст формы может пересоздаваться. Если между открытием документа и его проверкой пользователь совершил действие, вызвавшее возврат на клиент, а затем снова на сервер, значения в Перем могут быть потеряны. Именно поэтому реквизиты формы — самый надежный способ хранения данных "между делом".

Эффективное сравнение больших таблиц

Если в вашем документе тысячи строк, перебор в цикле Для каждого будет работать медленно. В таких случаях мы рекомендуем использовать временные таблицы в запросе.

Разберем алгоритм:

  1. Помещаем старую ТЧ (из хранилища или реквизита) во временную таблицу №1.
  2. Помещаем текущую ТЧ объекта во временную таблицу №2.
  3. Выполняем запрос с ПОЛНОЕ СОЕДИНЕНИЕ по всем полям.
  4. Если в результате запроса появились строки, где одна из сторон ЕСТЬ NULL, значит, данные изменились (строка добавлена, удалена или изменен реквизит).

Этот метод работает на уровне СУБД и является максимально производительным для больших объемов данных.

Заключение

Мы рассмотрели различные подходы к хранению и передаче данных табличной части внутри формы документа. Выбор метода зависит от ваших целей:

Использование этих приемов позволит вам создавать надежные и быстрые расширения, которые корректно отслеживают действия пользователей и программных алгоритмов.

← На главную