Загрузка данных из внешних файлов XML — это одна из наиболее часто встречающихся задач при интеграции различных систем на базе платформы «1С:Предприятие 8». В данной статье мы подробно разберем, как реализовать механизм загрузки данных напрямую в регистр сведений, минуя промежуточные таблицы значений, и как оптимизировать этот процесс для обеспечения максимальной производительности.
Рассмотрим ситуацию: у нас есть файл XML, содержащий данные об остатках товаров (номенклатура, производитель, количество). Нам необходимо прочитать этот файл и записать данные в регистр сведений Остатки. Часто начинающие разработчики используют промежуточную таблицу значений (ТЗ), что создает лишнюю нагрузку на оперативную память. Мы же разберем, как сделать это эффективно.
Основная проблема при прямой записи в регистр обычно заключается либо в неправильном использовании объекта НаборЗаписей, либо в низкой скорости при использовании объекта МенеджерЗаписи. Разберем оба подхода.
Объект НаборЗаписей предназначен для массовой работы с данными регистра. Основная ошибка, которую совершают разработчики — вызов метода Записать() внутри цикла обхода данных 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.Закрыть();
КонецПроцедуры
Преимущества этого метода: данные записываются одной транзакцией, что в десятки раз быстрее построчной записи. Особенности: метод подходит, если вы загружаете порцию данных, которая полностью заменяет старые записи по установленному отбору.
Если специфика задачи требует добавления записей по одной без удаления существующих данных по другим измерениям, используется МенеджерЗаписи. Чтобы этот метод не «тормозил», необходимо использовать явное управление транзакциями.
&НаСервере
Процедура ЗагрузитьМенеджером(ИмяФайла, ПрефиксБазы)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Данные = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Начинаем транзакцию для ускорения процесса
НачатьТранзакцию();
Попытка
Для Каждого СтрXDTO Из Данные.ТЧ Цикл
Менеджер = РегистрыСведений.Остатки.СоздатьМенеджерЗаписи();
Менеджер.Префикс = ПрефиксБазы;
Менеджер.Номенклатура = СтрXDTO.Номенклатура;
Менеджер.Производитель = СтрXDTO.Производитель;
Менеджер.ОстатокТовара = Число(СтрXDTO.ОстатокТовара);
// Записываем каждую строку
Менеджер.Записать(Истина);
КонецЦикла;
// Фиксируем все изменения разом
ЗафиксироватьТранзакцию();
Исключение
// В случае ошибки откатываем всё состояние БД к исходному
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("ЗагрузкаXML", УровеньЖурналаРегистрации.Ошибка, , , ИнформацияОбОшибке().Описание);
ВызватьИсключение "Ошибка при записи в регистр!";
КонецПопытки;
ЧтениеXML.Закрыть();
КонецПроцедуры
При реализации загрузки важно обратить внимание на следующие технические аспекты, которые часто упускаются из виду:
ОстатокТовара имеет тип Число, использование функции Формат() при записи будет ошибкой, так как она возвращает строку. Для корректной записи всегда приводите значения к нужному типу с помощью функций Число(), Дата() или выполняя поиск ссылочных объектов (например, через Справочники.Номенклатура.НайтиПоНаименованию()).ФабрикаXDTO.ПрочитатьXML() загружает весь файл в память. Если ваш файл весит 500 МБ и более, сервер может аварийно завершить работу. В таких случаях рекомендуем использовать последовательное чтение через ЧтениеXML.Прочитать(), анализируя тип узла и имя.D:\file.xml. В клиент-серверном варианте сервер 1С не имеет доступа к локальным дискам пользователя. Правильнее использовать ПоместитьФайл() для передачи файла с клиента во временное хранилище на сервер.ОповеститьОбИзменении(Тип("РегистрСведенийКлючЗаписи.Остатки")). Это позволит открытым формам списков автоматически обновить данные без полной перерисовки интерфейса методом ОбновитьИнтерфейс().Использование правильного метода записи (НаборЗаписей) в сочетании с грамотной обработкой типов данных позволяет сократить время загрузки в несколько раз и избежать типичных ошибок блокировок базы данных.