Как изменить порядок загрузки связанных объектов в 1С:Конвертация данных и избежать ошибки "Объект не найден"

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

При настройке регулярного обмена данными между конфигурациями «1С:Предприятие» (например, между «Управление торговлей» и «Бухгалтерия предприятия») разработчики часто сталкиваются с ситуацией, когда связанные объекты приходят в базу-приемник в неверной последовательности. Типичный пример: в файле выгрузки XML сначала идет зависимый регистр сведений, а только затем — документ, на который этот регистр ссылается. Если в базе-приемнике на этот регистр навешена подписка на событие ПриЗаписи, которая пытается прочитать реквизиты еще не созданного документа, система выдает ошибку, а в измерениях или реквизитах записывается битая ссылка со значением <объект не найден>.

В этой статье мы подробно проанализируем причины изменения порядка выгрузки объектов при обмене, разберем влияние СУБД на этот процесс и рассмотрим три практических способа решения данной проблемы, включая корректное использование функции ВыгрузитьПоПравилу в программных обработчиках Конвертации данных 2.1.

Выясняем причину: почему внезапно изменился порядок объектов в XML?

Многие разработчики ошибочно полагают, что правила обмена жестко регламентируют порядок следования объектов в выгружаемом XML-пакете. Однако, если обмен выполняется в автоматическом режиме по планам обмена, это не так. Рассмотрим, как устроен этот механизм изнутри:

  1. При регистрации изменений в планах обмена данные записываются в специальные таблицы регистрации (таблицы вида _ChngRng на уровне СУБД).
  2. В момент выполнения обмена платформа 1С делает запрос к этим таблицам для выборки измененных данных. На уровне платформы этот запрос формируется без явного указания сортировки (конструкции ORDER BY в SQL-запросе).
  3. Поведение СУБД-оптимизатора (MS SQL Server, PostgreSQL и др.) без жестко заданной сортировки не гарантирует стабильного порядка выдачи строк. Порядок строк в выборке зависит от физического расположения данных на диске, актуальности статистик таблиц и индексов.
  4. Любое обновление конфигурации, снятие с поддержки, добавление новых объектов метаданных (даже если они не участвуют в обмене) или регламентные операции на сервере баз данных могут привести к перестроению индексов и обновлению планов запросов СУБД. В результате порядок выборки измененных объектов кардинально меняется: если вчера СУБД сначала отдавала документы, а затем регистры, то сегодня она может начать отдавать их в обратном порядке.

Таким образом, полагаться на то, что объекты всегда будут загружаться в определенной последовательности «сами по себе», категорически нельзя. Правила обмена и логика базы-приемника должны проектироваться с учетом того, что любой объект может быть загружен раньше или позже связанных с ним данных.

Главная архитектурная ошибка: игнорирование режима загрузки

Прежде чем перейти к исправлению правил конвертации, важно обратить внимание на ключевой стандарт разработки фирмы «1С». Запуск тяжелой бизнес-логики (заполнение зависимых регистров, проведение других документов) в момент записи объекта во время обмена — это серьезная архитектурная ошибка.

Любые подписки на события ПередЗаписью и ПриЗаписи в конфигурации-приемнике должны в обязательном порядке содержать проверку на то, выполняется ли запись в режиме загрузки данных обмена. Если этот флаг равен значению Истина, выполнение транзакционной бизнес-логики должно блокироваться:


Если Источник.ОбменДанными.Загрузка Тогда
    Возврат;
EndIf;

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

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

Решение 1. Принудительная выгрузка объекта через ВыгрузитьПоПравилу

Самый быстрый способ гарантировать, что документ-основание будет записан в базу-приемник раньше, чем начнется загрузка ссылающегося на него регистра — принудительно выгрузить этот документ в XML-файл перед самим регистром. Для этого мы можем использовать возможности программных обработчиков «Конвертации данных 2.1».

Разберем алгоритм настройки по шагам:

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

Напишем следующий программный код в обработчике свойства:


// Проверяем, что значение ссылки заполнено
Если ЗначениеЗаполнено(Значение) Тогда
    
    // Принудительно выгружаем объект-ссылку по нужному правилу конвертации (ПКО)
    // Важно передать седьмой параметр (ТолькоПолучитьУзелСсылки) как Ложь
    ВыгрузитьПоПравилу(Значение, , , , "ПКО_ИмяВашегоДокумента", , Ложь);
    
EndIf;

Проанализируем ключевые параметры функции ВыгрузитьПоПравилу, которые мы использовали:

Благодаря этому при чтении XML-файла в базе-приемнике сначала полностью создастся и запишется наш документ, и только затем начнется загрузка записи регистра. В момент срабатывания подписки на событие регистра документ уже будет гарантированно существовать в базе данных.

Решение 2. Корректировка иерархии Правил Выгрузки Данных (ПВД)

Этот способ применим в тех случаях, когда обмен выполняется интерактивно пользователями с помощью обработки «Универсальный обмен данными в формате XML», то есть выгрузка идет не по зарегистрированным изменениям плана обмена, а по ПВД.

Порядок выгрузки объектов в XML-файл при ручном обмене напрямую зависит от порядка расположения Правил Выгрузки Данных в дереве настроек конвертации данных. Проанализируем структуру и настроим ее правильно:

  1. Перейдем в раздел «Правила выгрузки данных» в КД 2.1.
  2. Расположим правила по принципу «от независимых к зависимым».
  3. Правила выгрузки для справочников и документов должны располагаться на самом верху списка.
  4. Правила выгрузки для регистров сведений и регистров накопления должны находиться в самом низу дерева правил.

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

Решение 3. Использование механизма отложенного заполнения (Глобальные обработчики)

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

Вместо того чтобы мгновенно выполнять ресурсоемкие расчеты и запись в регистр РЕГ2 при загрузке каждой строки регистра РЕГ1, мы можем перенести эту задачу на этап, когда весь XML-файл гарантированно прочитан, а все объекты созданы.

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

  1. В подписке на событие записи регистра РЕГ1 при включенном режиме загрузки мы не выполняем никаких расчетов. Вместо этого мы помещаем ссылки на измененные документы во временное хранилище или в специальный глобальный список параметров (например, в параметры обработчика обмена).
  2. В «Конвертации данных 2.1» открываем настройки самой конвертации и переходим на вкладку «Глобальные обработчики».
  3. Находим событие «После загрузки данных». Этот обработчик выполняется платформой ровно один раз, когда чтение XML-файла полностью завершено и все транзакции по записи объектов зафиксированы.
  4. Пишем в данном обработчике код, который получает накопленный список документов, обходит их в цикле и выполняет для каждого регламентный пересчет и заполнение зависимого регистра РЕГ2.

Пример шаблона кода в обработчике «После загрузки данных»:


// Проверяем наличие накопленного списка документов в параметрах конвертации
Если Параметры.Свойство("СписокДокументовДляОбработки") И ТипЗнч(Параметры.СписокДокументовДляОбработки) = Тип("Массив") Тогда
    
    Для Каждого СсылкаНаДокумент Из Параметры.СписокДокументовДляОбработки Цикл
        
        // На данном этапе документ гарантированно создан и записан в СУБД
        // Мы можем безопасно читать любые его реквизиты и заполнять связанные регистры
        РегистрыСведений.РЕГ2.ЗаполнитьПоДокументу(СсылкаНаДокумент);
        
    КонецЦикла;
    
КонецЕсли;

Такой подход полностью исключает возникновение ошибок типа «Объект не найден» и значительно ускоряет время прохождения обмена, так как исключает многократную перезапись одних и тех же данных в процессе импорта.

← На главную