При разработке систем интеграции, например, выгрузки номенклатуры на сайт, механизм планов обмена в 1С является стандартом де-факто. Однако начинающие разработчики часто сталкиваются с риском потери данных в момент выгрузки. Давайте разберем, как построить надежный процесс обмена, который исключит дублирование и, что более важно, потерю изменений, произошедших прямо во время сеанса связи.
Для начала проанализируем, как система отслеживает изменения. План обмена хранит информацию о зарегистрированных изменениях для каждого узла. Ключевым моментом является использование номеров сообщений. У каждого узла в плане обмена есть два важных свойства: Номер отправленного сообщения и Номер принятого сообщения.
Когда мы собираемся выгрузить данные, мы не просто считываем список объектов, а помечаем этот набор данных определенным номером. Рассмотрим этот процесс по шагам:
НомерОтправленного + 1).ВыбратьИзменения(), передавая этот номер. Система «помечает» все текущие изменения этим номером.Разберем, как программно инициировать процесс выборки. Основной метод, который нам понадобится — ВыбратьИзменения(). Он возвращает объект ВыборкаИзмененийПланаОбмена, который можно обойти в цикле.
Рассмотрим пример кода для инициации выгрузки:
// Получаем ссылку на узел, для которого выполняем выгрузку
УзелОбъекта = ПланыОбмена.Сайт.НайтиПоКоду("SITE_01");
Узел = УзелОбъекта.ПолучитьОбъект();
// Увеличиваем номер сообщения
Узел.НомерОтправленного = Узел.НомерОтправленного + 1;
Узел.Записать();
НовыйНомер = Узел.НомерОтправленного;
// Выбираем изменения, помеченные этим номером
Выборка = ПланыОбмена.ВыбратьИзменения(Узел.Ссылка, НовыйНомер);
Пока Выборка.Следующий() Цикл
Данные = Выборка.Получить();
// Здесь логика обработки данных (например, сериализация в JSON)
Если ТипЗнч(Данные) = Тип("СправочникОбъект.Номенклатура") Тогда
// Обработка номенклатуры
ИначеЕсли ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
// Обработка удаления объекта
КонецЕсли;
КонецЦикла;
Важно помнить, что если в плане обмена участвует несколько типов объектов (например, Номенклатура и УпаковкиЕдиницыИзмерения), выборка вернет их все вперемешку. Нам нужно проверять тип полученных данных с помощью функции ТипЗнч().
Самый критичный момент — это пункт 2.2 из обсуждения: что делать, если данные изменились во время работы нашего кода? Если мы просто очистим всю регистрацию по узлу после успешной выгрузки, мы «затрем» те изменения, которые еще не были выгружены.
Для решения этой проблемы используется метод УдалитьРегистрациюИзменений(), в который передается номер сообщения. Рассмотрим логику подробнее:
Метод ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерСообщения) удаляет только те записи из таблиц регистрации изменений, чей номер сообщения меньше или равен переданному значению. Те изменения, которые возникли во время выгрузки и не получили номер сообщения (или получили номер 0), останутся в плане обмена и будут выбраны при следующем запуске процесса.
// Этот блок кода выполняется только ПОСЛЕ подтверждения от сайта
Если ОтветСайта.КодСостояния = 200 Тогда
// Удаляем изменения только для конкретного номера сообщения
ПланыОбмена.УдалитьРегистрациюИзменений(Узел.Ссылка, НовыйНомер);
// Обновляем номер принятого сообщения, чтобы синхронизироваться
Узел.НомерПринятого = НовыйНомер;
Узел.Записать();
КонецЕсли;
Хотя метод ВыбратьИзменения() прост в использовании, профессиональная разработка часто требует применения запросов. У каждого объекта, включенного в план обмена, появляется виртуальная таблица Изменения. Например, Справочник.Номенклатура.Изменения.
Проанализируем преимущества запросов к этим таблицам:
ВЫБРАТЬ ПЕРВЫЕ... в запросе легко реализовать порционную выгрузку (пачками по 100-500 элементов), что критично для стабильности работы веб-сервисов.Пример запроса к таблице изменений:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураИзменения.Ссылка КАК Ссылка,
| НоменклатураИзменения.НомерСообщения КАК НомерСообщения
|ИЗ
| Справочник.Номенклатура.Изменения КАК НоменклатураИзменения
|ГДЕ
| НоменклатураИзменения.Узел = &Узел
| И (НоменклатураИзменения.НомерСообщения <= &НомерСообщения ИЛИ НоменклатураИзменения.НомерСообщения ЕСТЬ NULL)";
Запрос.УстановитьПараметр("Узел", УзелСсылка);
Запрос.УстановитьПараметр("НомерСообщения", НовыйНомер);
Результат = Запрос.Выполнить();
Часто программисты забывают о физическом удалении объектов из базы. Если пользователь удалит карточку номенклатуры (не установит пометку удаления, а именно удалит объект), в плане обмена зарегистрируется запись типа УдалениеОбъекта. Это специальный объект, который содержит только ссылку на удаленный элемент (которая уже не ведет ни на какие данные в базе).
При обходе выборки или анализе запроса обязательно учитывайте этот тип. Если вы получили УдалениеОбъекта, необходимо отправить на сайт команду DELETE или скрыть товар в каталоге, так как данных по нему в 1С больше не существует.
Выясним причину возможных сбоев: если вы вызываете УдалитьРегистрациюИзменений до того, как сайт подтвердил получение данных, вы рискуете потерять информацию при обрыве связи. Правильный алгоритм всегда строится по принципу: Сначала подтверждение — потом очистка.
Если ваша конфигурация построена на БСП (Библиотека стандартных подсистем), рекомендуем использовать встроенную подсистему «Обмен данными». Она берет на себя большинство рутинных задач: логирование ошибок, мониторинг очереди изменений и работу с транспортными сообщениями. Однако понимание базовых механизмов работы ПланыОбмена, которое мы разобрали выше, необходимо любому разработчику для отладки и написания собственных легких интеграций.
Подводя итог, можно сказать: грамотная работа с планом обмена заключается не в простом получении списка ссылок, а в строгом контроле номеров сообщений и правильном моменте очистки регистрации. Это гарантирует, что ни одно изменение не «проскочит» мимо сайта, даже в условиях интенсивной работы пользователей в базе.