Как обработать десериализованную таблицу значений с иерархическим справочником в 1С?

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

При организации обмена данными между информационными базами 1С через веб-сервисы частой задачей является передача справочников. На стороне источника данные формируются с помощью запроса и выгружаются в таблицу значений, после чего сериализуются в XML. На стороне приемника после выполнения десериализации с помощью объекта СериализаторXDTO мы получаем таблицу значений. Однако встает вопрос: каким образом правильным и безопасным путем записать полученные данные в иерархический справочник Номенклатура?

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

Базовый алгоритм загрузки данных из таблицы значений

Разберем классический подход к обходу таблицы значений и программному созданию или обновлению элементов справочника. Главная задача — правильно определить тип записи (группа или элемент), проверить существование ссылки в базе-приемнике и корректно перенести реквизиты.

Посмотрим на пример кода обработки десериализованной таблицы значений:


Для Каждого Стр Из ТЗ Цикл
    Попытка
        ЭтоГруппа = Ложь;
        Если ТЗ.Колонки.Найти("ЭтоГруппа") <> Неопределено Тогда
            ЭтоГруппа = Стр.ЭтоГруппа;
        КонецЕсли;

        // Проверяем существование объекта в базе по ссылке
        Если Стр.Ссылка.ПолучитьОбъект() = Неопределено Тогда
            Нов = ?(НЕ ЭтоГруппа, Справочники["Номенклатура"].СоздатьЭлемент(), Справочники["Номенклатура"].СоздатьГруппу());
            Нов.УстановитьСсылкуНового(Стр.Ссылка);
        Иначе
            Нов = Стр.Ссылка.ПолучитьОбъект();
        КонецЕсли;

        // Заполняем реквизиты объекта
        Если НЕ ЭтоГруппа Тогда
            ЗаполнитьЗначенияСвойств(Нов, Стр, , "Ссылка");
        Иначе
            ЗаполнитьЗначенияСвойств(Нов, Стр, "Наименование, Код, Родитель");
        КонецЕсли;

        // Отключаем проверки платформы для режима загрузки
        Нов.ОбменДанными.Загрузка = Истина;
        Нов.Записать();
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Разбор ключевых методов и флагов

Проанализируем детально, как работают использованные в алгоритме механизмы платформы 1С:

  1. ПолучитьОбъект() — вызванный у десериализованной ссылки Стр.Ссылка, возвращает Неопределено, если объект с таким уникальным идентификатором (GUID) еще не существует в информационной базе приемника. Это позволяет однозначно понять, требуется ли создавать новый элемент или нужно модифицировать существующий.
  2. УстановитьСсылкуНового() — метод, позволяющий сопоставить создаваемому объекту ровно тот GUID, который был у него в базе-источнике. Важно помнить, что этот метод можно вызывать только для новых, еще ни разу не записанных в информационную базу объектов до вызова метода Записать().
  3. ЗаполнитьЗначенияСвойств() — копирует значения одноименных колонок таблицы значений в реквизиты объекта. Для элемента исключается копирование поля Ссылка, а для группы заполняются только специфичные реквизиты иерархии.
  4. ОбменДанными.Загрузка = Истина — специальный флаг, который отключает выполнение подписок на события, проверки заполнения обязательных реквизитов и дополнительную бизнес-логику при записи. Это критически важно при интеграционных обменах для избежания конфликтов и циклических вызовов.

Важные нюансы при работе с иерархией и ссылочными типами

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

  1. Нарушение порядка иерархии: Если в таблице значений дочерний элемент записан раньше своей родительской группы, ссылка на родителя укажет на еще не созданный объект. Чтобы избежать появления «битых» ссылок в реквизите Родитель, рекомендуется либо заранее сортировать таблицу значений по уровню иерархии (сначала группы верхних уровней, затем элементы), либо использовать двухпроходную запись (на первом проходе создаются все объекты с их GUID, на втором — заполняются реквизиты и связи).
  2. Потеря табличных частей: Простой запрос к таблице справочника без выгрузки связанных табличных частей передает только реквизиты шапки. Если номенклатура содержит единицы измерения или дополнительные реквизиты, они не попадут в ТЗ.
  3. Оптимизация скорости записи: Запись каждого элемента в отдельном вызове без использования транзакций существенно снижает скорость обмена. При больших объемах данных рекомендуется использовать порционные транзакции через НачатьТранзакцию() и ЗафиксироватьТранзакцию() каждые 500–1000 элементов.

Альтернативный вариант: сериализация объектов СправочникОбъект напрямую

Если справочники в базах полностью идентичны, более правильным архитектурным решением является сериализация не таблицы значений, а самого объекта СправочникОбъект через СериализаторXDTO. При таком подходе платформа автоматически сохраняет УИД, все реквизиты и табличные части объекта. На стороне приемника вызов СериализаторXDTO.ПрочитатьXML() сразу восстановит готовый объект справочника, у которого достаточно установить ОбменДанными.Загрузка = Истина и вызвать метод Записать().

← На главную