В практике разработки на платформе 1С:Предприятие 8.3 часто возникает специфическая задача: необходимо зафиксировать состояние табличной части (ТЧ) документа в момент его открытия, чтобы позже, например, при записи или закрытии формы, сравнить эти данные с измененными. Это особенно актуально при создании расширений, когда сторонняя обработка или стандартные механизмы могут программно менять данные, и нам нужно отследить эти изменения для выполнения дополнительной логики или проверок.
Рассмотрим подробно несколько эффективных способов реализации этой задачи, проанализируем их преимущества и недостатки, а также разберем примеры кода для каждого случая.
Это один из самых надежных и простых в реализации способов. Мы создаем в форме документа дополнительный реквизит, который будет хранить "слепок" нашей табличной части. Поскольку расширения позволяют добавлять новые реквизиты формы, мы можем использовать этот механизм без изменения основной конфигурации.
Проанализируем алгоритм действий:
КопияТЧ) и назначаем ему тип ТаблицаЗначений.ПриСозданииНаСервере или ПриЧтенииНаСервере выполняем выгрузку данных.Рассмотрим пример кода:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Выгружаем данные из основной ТЧ документа в наш вспомогательный реквизит формы
// Предположим, ТЧ называется "Товары"
ЗначениеВРеквизитФормы(Объект.Товары.Выгрузить(), "КопияТЧ");
КонецПроцедуры
&НаСервере
Процедура ПроверитьИзмененияНаСервере()
// Получаем текущее состояние ТЧ и ранее сохраненное
ТекущаяТЧ = Объект.Товары.Выгрузить();
СтараяТЧ = РеквизитФормыВЗначение("КопияТЧ");
// Теперь мы можем сравнить две таблицы значений
// Например, через цикл или построив запрос
КонецПроцедуры
Преимущество: Данные всегда под рукой на сервере в типизированном виде, их удобно сравнивать и обрабатывать.
Если мы не хотим загромождать форму лишними реквизитами или данных слишком много, целесообразно использовать Временное хранилище. Этот метод позволяет сохранить любой сериализуемый объект (массив, структуру, таблицу значений) в оперативной памяти сервера, привязав его к уникальному идентификатору формы.
Разберем, как это работает по шагам:
УникальныйИдентификатор формы.Пример реализации:
&НаСервере
Процедура СохранитьТЧВоХранилище()
// Создаем слепок данных
ТЗ_Копия = Объект.Товары.Выгрузить();
// Помещаем во временное хранилище.
// Указываем УникальныйИдентификатор формы, чтобы данные удалились вместе с закрытием формы.
АдресХранилища = ПоместитьВоВременноеХранилище(ТЗ_Копия, ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры
&НаСервере
Процедура СравнитьДанныеИзХранилища()
// Проверяем, есть ли адрес
Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда
СтараяТЧ = ПолучитьИзВременногоХранилища(АдресХранилища);
// Логика сравнения...
КонецЕсли;
КонецПроцедуры
Важный момент: Переменная АдресХранилища должна быть реквизитом формы (тип Строка), чтобы она сохраняла свое значение между серверными вызовами.
Иногда требуется передавать данные не только на сервере, но и на клиенте. ТаблицаЗначений не живет на стороне клиента, поэтому в таких случаях мы используем Массив, элементами которого являются Структуры.
Проанализируем ситуацию: если нам нужно передать данные из серверной процедуры в клиентскую, а затем снова на сервер, массив структур — отличный выбор.
Рассмотрим пример формирования такого массива:
&НаСервере
Функция ПолучитьМассивСтруктурТЧ()
МассивРезультат = Новый Массив;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
СтруктураСтроки = Новый Структура;
СтруктураСтроки.Вставить("Номенклатура", СтрокаТЧ.Номенклатура);
СтруктураСтроки.Вставить("Количество", СтрокаТЧ.Количество);
СтруктураСтроки.Вставить("Цена", СтрокаТЧ.Цена);
МассивРезультат.Добавить(СтруктураСтроки);
КонецЦикла;
Возврат МассивРезультат;
КонецФункции
Этот массив можно хранить в обычном реквизите формы с типом Произвольный. Он будет доступен в любой процедуре модуля формы.
Для оптимизации передачи данных между клиентом и сервером можно использовать JSON-сериализацию. Мы превращаем всю таблицу значений в одну длинную строку. Это особенно полезно, если вы хотите минимизировать нагрузку на контекст формы.
Рассмотрим, как это реализовать:
В момент открытия мы преобразуем ТЧ в JSON и сохраняем в скрытый реквизит формы. При записи документа мы снова преобразуем текущую ТЧ в JSON и просто сравниваем две строки. Если строки идентичны — значит, ничего не менялось. Это избавляет нас от необходимости писать сложные циклы сравнения по каждой колонке.
Работая с расширениями, важно помнить, что мы часто перехватываем события через аннотации &Перед, &После или &Вместо. Если наша задача — поймать момент, когда сторонняя обработка изменила документ и записала его, лучше всего использовать Подписку на событие или расширение метода ПередЗаписьюНаСервере.
Выясним причину, почему переменные модуля (объявленные через Перем) — это не всегда хорошее решение. В управляемом приложении серверный контекст формы может пересоздаваться. Если между открытием документа и его проверкой пользователь совершил действие, вызвавшее возврат на клиент, а затем снова на сервер, значения в Перем могут быть потеряны. Именно поэтому реквизиты формы — самый надежный способ хранения данных "между делом".
Если в вашем документе тысячи строк, перебор в цикле Для каждого будет работать медленно. В таких случаях мы рекомендуем использовать временные таблицы в запросе.
Разберем алгоритм:
ПОЛНОЕ СОЕДИНЕНИЕ по всем полям.ЕСТЬ NULL, значит, данные изменились (строка добавлена, удалена или изменен реквизит).Этот метод работает на уровне СУБД и является максимально производительным для больших объемов данных.
Мы рассмотрели различные подходы к хранению и передаче данных табличной части внутри формы документа. Выбор метода зависит от ваших целей:
Использование этих приемов позволит вам создавать надежные и быстрые расширения, которые корректно отслеживают действия пользователей и программных алгоритмов.