Как правильно загрузить данные из XML и записать их в документы 1С

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

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

Анализ основной проблемы: Почему данные не записываются?

Проанализируем исходный код и выясним причину, по которой поиск выполняется успешно, но записи в базу не происходит. Главная ошибка кроется в работе с транзакциями. В 1С существует жесткое правило: количество вызовов функции НачатьТранзакцию() должно строго соответствовать количеству вызовов ЗафиксироватьТранзакцию().

В представленном коде НачатьТранзакцию() вызывается внутри цикла по выборке документов, а ЗафиксироватьТранзакцию() — за пределами всех циклов в самом конце процедуры. В результате, если в файле было 100 строк, система 100 раз «начала» транзакцию, но только один раз попыталась её «зафиксировать». Для платформы это означает, что транзакция не была завершена корректно, и при выходе из процедуры происходит неявный откат (rollback) всех изменений. Именно поэтому данные в базе не сохраняются.

Решение проблемы с транзакциями

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


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

Оптимизация производительности: Уходим от запросов в цикле

Еще одна критическая проблема — выполнение запроса к базе данных на каждой итерации чтения XML. Если в вашем файле 10 000 строк, программа сделает 10 000 отдельных обращений к SQL-серверу. Это крайне неэффективно и может «положить» сервер при большом объеме данных. Проанализируем, как сделать загрузку быстрее.

Правильный подход заключается в следующем: сначала мы считываем весь XML-файл в Таблицу Значений, а затем передаем эту таблицу в запрос в качестве параметра. Это позволит найти все необходимые документы одним махом. Рассмотрим шаги реализации:

  1. Создаем таблицу значений с колонками Цена, Количество, Дата.
  2. Заполняем её данными из XML через ЧтениеXML.
  3. Передаем таблицу в запрос и соединяем её с таблицей документов по условиям.
  4. Обрабатываем результат запроса и записываем данные.

Работа с документом-основанием

Согласно условию задачи, если у документа есть основание, оценка должна записываться и в основной документ, и в документ-основание. Важно помнить, что нельзя изменить данные документа-основания просто через точку: Объект.ДокументОснование.Качество = Оценка — это приведет к ошибке или отсутствию результата, так как через точку доступна только ссылка на объект, а не сам объект для редактирования.

Выясним, как сделать это правильно:


Если ЗначениеЗаполнено(Выборка.ДокументОснование) Тогда
    ОбъектОснование = Выборка.ДокументОснование.ПолучитьОбъект();
    ОбъектОснование.Качество = Оценка;
    Попытка
        ОбъектОснование.Записать();
    Исключение
        Сообщить("Не удалось записать документ-основание");
    КонецПопытки;
КонецЕсли;

Нюансы сравнения дат и чисел

Проанализируем условие ПоступлениеТовара.Дата = &DATE. В 1С дата содержит время до секунды. Если в XML указана дата без времени или время отличается хотя бы на секунду, документ не будет найден. Чтобы избежать этого, рекомендуется использовать функцию НАЧАЛОПЕРИОДА в запросе или искать документы в интервале времени.

Также обратим внимание на сравнение чисел (Цена и Количество). В запросах SQL сравнение дробных чисел может работать нестабильно из-за особенностей хранения точности. Если вы сталкиваетесь с тем, что документ «не находится», попробуйте использовать в запросе условие МЕЖДУ с небольшой погрешностью или убедитесь, что типы данных в параметрах запроса и в базе данных идентичны.

Использование режима загрузки

В коде автора используется свойство ОбменДанными.Загрузка = Истина. Рассмотрим, на что это влияет. Данный флаг отключает большинство проверок в модуле объекта и подписках на события. Это значительно ускоряет запись, но будьте осторожны: если изменение поля «Качество» должно влечь за собой пересчет каких-то итогов или движений по регистрам, при включенном режиме Загрузка эти действия не выполнятся. Используйте этот режим только в тех случаях, когда вы уверены, что дополнительные проверки не нужны.

Заключение и советы

Разберем краткий чек-лист для подобных задач:

  1. Проверяйте логику транзакций: Всегда следите, чтобы на каждое НачатьТранзакцию приходилось ЗафиксироватьТранзакцию в той же логической ветке.
  2. Не используйте Возврат в циклах: Если данных для одной строки файла нет, используйте Продолжить, иначе вся обработка прервется на первой же ошибке.
  3. Закрывайте файлы: После работы с ЧтениеXML обязательно вызывайте Чтение.Закрыть(), чтобы файл не оставался заблокированным в системе.
  4. Используйте отладку: Если данные не записываются, поставьте точку останова на строке Объект.Записать() и проверьте, заходит ли туда код и не вылетает ли он в блок Исключение.

Соблюдение этих правил позволит вам создавать надежные и быстрые механизмы интеграции 1С с внешними системами.

← На главную