При разработке внешних обработок для синхронизации данных между 1С и внешними системами (например, базами MySQL) часто возникает задача минимизации трафика. Если мы просто перезаписываем все данные из таблицы обработки обратно в регистр, это создает лишнюю нагрузку и инициирует ненужные события в системе. Рассмотрим подробнее, как эффективно определить, какие именно записи были изменены пользователем в форме обработки, чтобы отправить во внешнюю базу только дельту изменений.
Это самый наглядный и часто используемый метод в управляемых формах. Суть заключается в том, чтобы хранить «слепок» данных в момент их загрузки в обработку. Проанализируем ситуацию: когда мы заполняем таблицу на форме данными из регистра, мы создаем для каждой строки её копию.
Разберем по шагам реализацию этого метода:
ДанныеОригинал с типом Строка или Произвольный.Рассмотрим пример кода для упаковки данных в JSON при загрузке:
// При загрузке данных в таблицу формы
Для Каждого СтрокаТЗ Из Объект.ТаблицаДанных Цикл
СтруктураСостояния = Новый Структура;
СтруктураСостояния.Вставить("Колонка1", СтрокаТЗ.Колонка1);
СтруктураСостояния.Вставить("Колонка2", СтрокаТЗ.Колонка2);
СтруктураСостояния.Вставить("Колонка3", СтрокаТЗ.Колонка3);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураСостояния);
СтрокаТЗ.ДанныеОригинал = ЗаписьJSON.Закрыть();
КонецЦикла;
Теперь выясним, как проверить изменения перед записью в регистр:
Для Каждого СтрокаТЗ Из Объект.ТаблицаДанных Цикл
СтруктураТекущая = Новый Структура("Колонка1, Колонка2, Колонка3",
СтрокаТЗ.Колонка1, СтрокаТЗ.Колонка2, СтрокаТЗ.Колонка3);
// Читаем оригинал
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаТЗ.ДанныеОригинал);
СтруктураОригинал = ПрочитатьJSON(ЧтениеJSON);
Если Не ДанныеРавны(СтруктураТекущая, СтруктураОригинал) Тогда
// Запись изменена — выполняем запись в регистр и отправку в MySQL
ЗаписатьВРегистрСведений(СтрокаТЗ);
ОтправитьВMySQL(СтрокаТЗ);
КонецЕсли;
КонецЦикла;
Проанализируем более профессиональный подход. Если ваша задача — синхронизация с внешней базой, то «правильнее» всего использовать штатный механизм регистрации изменений. Для этого независимый регистр сведений включается в состав ПланаОбмена.
Посмотрим, какие преимущества это дает: платформе безразлично, как именно была изменена запись (через вашу обработку, вручную в интерфейсе или другим программным кодом). Как только происходит вызов НаборЗаписей.Записать(), платформа фиксирует изменения для узла обмена.
Алгоритм работы в этом случае будет следующим:
ПланОбмена, назовем его СинхронизацияСMySQL.Авторегистрация в значение Разрешить.Пример получения измененных данных через план обмена:
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелMySQL, НомерСообщения);
Пока ВыборкаИзменений.Следующий() Цикл
Данные = ВыборкаИзменений.Получить();
Если ТипЗнч(Данные) = Тип("РегистрСведенийМенеджерЗаписи.НазваниеРегистра") Тогда
// Здесь мы имеем доступ к измененной записи
ОтправитьВMySQL(Данные);
КонецЕсли;
КонецЦикла;
Если в регистре очень много колонок (ресурсов и реквизитов), попарное сравнение в цикле может работать медленно. Разберем метод контрольных сумм. При загрузке данных мы вычисляем MD5-хеш или простую контрольную сумму по строке всех значений.
Посмотрим на пример функции вычисления хеша:
Функция ПолучитьХешСтроки(СтрокаДанных)
ТекстДляХеша = Строка(СтрокаДанных.Колонка1) + "|" +
Строка(СтрокаДанных.Колонка2) + "|" +
Строка(СтрокаДанных.Колонка3);
Хеширование = Новый ХешированиеДанных(ХешФункция.MD5);
Хеширование.Добавить(ТекстДляХеша);
Возврат Хеширование.ХешСумма;
КонецФункции
Важный момент: при записи вам достаточно сравнить две короткие строки (хеши), что значительно ускоряет работу с большими таблицами значений на стороне клиента.
Иногда данных настолько много, что перебор в цикле на клиенте неэффективен. В таком случае мы можем использовать мощь языка запросов 1С. Выясним, как это реализовать:
ЛЕВОЕ СОЕДИНЕНИЕ этой таблицы с реальной таблицей регистра сведений по измерениям.ГДЕ прописываем условие: ГДЕ Таблица.Ресурс1 <> Регистр.Ресурс1 ИЛИ Таблица.Ресурс2 <> Регистр.Ресурс2.Этот запрос вернет нам только те строки, которые действительно отличаются от того, что хранится в базе данных. Это гарантирует, что если пользователь открыл строку, ничего не менял, но нажал «Сохранить», запись не будет считаться измененной.
Рассмотрим ситуацию, когда вам нужно в модуле набора записей регистра (событие ПередЗаписью) понять, что данные пришли именно из вашей обработки, а не из другого места. Для этого у объекта НаборЗаписей существует свойство ДополнительныеСвойства.
Пример передачи флага из обработки:
Набор = РегистрыСведений.НашРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Номенклатура.Установить(ВыбраннаяНоменклатура);
// ... заполнение набора ...
// Устанавливаем флаг источника
Набор.ДополнительныеСвойства.Вставить("ЭтоОбменMySQL", Истина);
Набор.Записать();
В модуле набора записей регистра:
Процедура ПередЗаписью(Отказ, Замещение)
Если ДополнительныеСвойства.Свойство("ЭтоОбменMySQL") Тогда
// Мы точно знаем, что запись инициирована нашей обработкой
// Здесь можно реализовать дополнительную логику логирования
КонецЕсли;
КонецПроцедуры
Подведем итоги: для решения задачи проверки изменений наиболее гибким является Метод 1 (скрытая колонка), так как он работает полностью в контексте формы. Если же вы строите масштабную систему синхронизации, рекомендуем обратить внимание на Метод 2 (планы обмена), который является стандартом платформы 1С:Предприятие 8.3 для отслеживания изменений данных.