Как загрузить данные из XML напрямую в регистр сведений 1С?

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

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

Постановка задачи и анализ исходной ситуации

Рассмотрим ситуацию: у нас есть файл XML, содержащий данные об остатках товаров (номенклатура, производитель, количество). Нам необходимо прочитать этот файл и записать данные в регистр сведений Остатки. Часто начинающие разработчики используют промежуточную таблицу значений (ТЗ), что создает лишнюю нагрузку на оперативную память. Мы же разберем, как сделать это эффективно.

Основная проблема при прямой записи в регистр обычно заключается либо в неправильном использовании объекта НаборЗаписей, либо в низкой скорости при использовании объекта МенеджерЗаписи. Разберем оба подхода.

Вариант 1: Использование объекта НаборЗаписей (Оптимально для групп данных)

Объект НаборЗаписей предназначен для массовой работы с данными регистра. Основная ошибка, которую совершают разработчики — вызов метода Записать() внутри цикла обхода данных XML. Это приводит к тому, что на каждой итерации система инициирует новую транзакцию и перезаписывает данные, что крайне медленно и может привести к ошибкам блокировок.

Проанализируем правильный алгоритм работы с набором записей:


&НаСервере
Процедура ЗагрузитьНаборомЗаписей(ИмяФайла, ПрефиксБазы)
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ИмяФайла);
    
    // Используем фабрику XDTO для быстрого чтения структуры
    ПриходыXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    
    // Создаем набор записей
    Набор = РегистрыСведений.Остатки.СоздатьНаборЗаписей();
    
    // ВАЖНО: Если нужно заменить данные только по определенному условию,
    // устанавливаем фильтр (отбор). Если отбор не установлен, 
    // метод Записать() может очистить весь регистр!
    Набор.Отбор.Префикс.Установить(ПрефиксБазы);
    
    // Обрабатываем список объектов из XML
    СписокXDTO = ?(ТипЗнч(ПриходыXDTO.ТЧ) = Тип("СписокXDTO"), ПриходыXDTO.ТЧ, Новый Массив);
    Если СписокXDTO.Количество() = 0 И ПриходыXDTO.ТЧ <> Неопределено Тогда
        СписокXDTO.Добавить(ПриходыXDTO.ТЧ);
    КонецЕсли;

    Для Каждого СтрокаXDTO ИЗ СписокXDTO Цикл
        НоваяЗапись = Набор.Добавить();
        НоваяЗапись.Префикс = ПрефиксБазы;
        НоваяЗапись.Номенклатура = СтрокаXDTO.Номенклатура;
        НоваяЗапись.Производитель = СтрокаXDTO.Производитель;
        
        // Преобразование типов: данные из XML часто приходят как строки
        НоваяЗапись.ОстатокТовара = Число(СтрокаXDTO.ОстатокТовара);
    КонецЦикла;
    
    // Записываем весь набор ОДНИМ вызовом вне цикла
    Набор.Записать(Истина); // Параметр Истина означает замещение записей по отбору
    
    ЧтениеXML.Закрыть();
    
КонецПроцедуры

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

Вариант 2: Использование Менеджера Записи (Построчная загрузка)

Если специфика задачи требует добавления записей по одной без удаления существующих данных по другим измерениям, используется МенеджерЗаписи. Чтобы этот метод не «тормозил», необходимо использовать явное управление транзакциями.


&НаСервере
Процедура ЗагрузитьМенеджером(ИмяФайла, ПрефиксБазы)
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ИмяФайла);
    Данные = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    
    // Начинаем транзакцию для ускорения процесса
    НачатьТранзакцию();
    
    Попытка
        Для Каждого СтрXDTO Из Данные.ТЧ Цикл
            Менеджер = РегистрыСведений.Остатки.СоздатьМенеджерЗаписи();
            Менеджер.Префикс = ПрефиксБазы;
            Менеджер.Номенклатура = СтрXDTO.Номенклатура;
            Менеджер.Производитель = СтрXDTO.Производитель;
            Менеджер.ОстатокТовара = Число(СтрXDTO.ОстатокТовара);
            
            // Записываем каждую строку
            Менеджер.Записать(Истина); 
        КонецЦикла;
        
        // Фиксируем все изменения разом
        ЗафиксироватьТранзакцию();
    Исключение
        // В случае ошибки откатываем всё состояние БД к исходному
        ОтменитьТранзакцию();
        ЗаписьЖурналаРегистрации("ЗагрузкаXML", УровеньЖурналаРегистрации.Ошибка, , , ИнформацияОбОшибке().Описание);
        ВызватьИсключение "Ошибка при записи в регистр!";
    КонецПопытки;
    
    ЧтениеXML.Закрыть();
    
КонецПроцедуры

Разберем важные нюансы оптимизации

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

  1. Проблема типизации данных. В XML-файлах данные хранятся в текстовом виде. Если в вашем регистре ресурс ОстатокТовара имеет тип Число, использование функции Формат() при записи будет ошибкой, так как она возвращает строку. Для корректной записи всегда приводите значения к нужному типу с помощью функций Число(), Дата() или выполняя поиск ссылочных объектов (например, через Справочники.Номенклатура.НайтиПоНаименованию()).
  2. Работа с большими файлами. Метод ФабрикаXDTO.ПрочитатьXML() загружает весь файл в память. Если ваш файл весит 500 МБ и более, сервер может аварийно завершить работу. В таких случаях рекомендуем использовать последовательное чтение через ЧтениеXML.Прочитать(), анализируя тип узла и имя.
  3. Безопасность путей. В коде не рекомендуется прописывать жесткие пути вроде D:\file.xml. В клиент-серверном варианте сервер 1С не имеет доступа к локальным дискам пользователя. Правильнее использовать ПоместитьФайл() для передачи файла с клиента во временное хранилище на сервер.
  4. Обновление интерфейса. После загрузки большого объема данных в регистр на клиенте стоит вызвать оповещение ОповеститьОбИзменении(Тип("РегистрСведенийКлючЗаписи.Остатки")). Это позволит открытым формам списков автоматически обновить данные без полной перерисовки интерфейса методом ОбновитьИнтерфейс().

Использование правильного метода записи (НаборЗаписей) в сочетании с грамотной обработкой типов данных позволяет сократить время загрузки в несколько раз и избежать типичных ошибок блокировок базы данных.

← На главную