Загрузка данных из внешних файлов — это классическая задача для разработчика 1С. На первый взгляд, алгоритм кажется простым: прочитать файл, найти соответствующий объект в базе и записать в него данные. Однако на практике часто возникают проблемы, связанные с производительностью, блокировками или банальными логическими ошибками в коде. Разберем ситуацию, когда данные из XML-файла (оценка товара) должны быть записаны в документ ПоступлениеТовара при совпадении цены, количества и даты.
Проанализируем исходный код и выясним причину, по которой поиск выполняется успешно, но записи в базу не происходит. Главная ошибка кроется в работе с транзакциями. В 1С существует жесткое правило: количество вызовов функции НачатьТранзакцию() должно строго соответствовать количеству вызовов ЗафиксироватьТранзакцию().
В представленном коде НачатьТранзакцию() вызывается внутри цикла по выборке документов, а ЗафиксироватьТранзакцию() — за пределами всех циклов в самом конце процедуры. В результате, если в файле было 100 строк, система 100 раз «начала» транзакцию, но только один раз попыталась её «зафиксировать». Для платформы это означает, что транзакция не была завершена корректно, и при выходе из процедуры происходит неявный откат (rollback) всех изменений. Именно поэтому данные в базе не сохраняются.
Рассмотрим, как правильно организовать запись данных. Нам необходимо перенести фиксацию транзакции внутрь цикла обработки каждого найденного документа. Это обеспечит сохранность данных даже в случае сбоя при обработке следующего документа. Разберем исправленную структуру:
Пока Выборка.Следующий() Цикл
НачатьТранзакцию();
Попытка
ОбъектПоступление = Выборка.ДокументПоступление.ПолучитьОбъект();
// Присвоение значений
ОбъектПоступление.Качество = Оценка;
ОбъектПоступление.Записать();
ЗафиксироватьТранзакцию(); // Теперь фиксация происходит после каждой записи
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при записи документа: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Еще одна критическая проблема — выполнение запроса к базе данных на каждой итерации чтения XML. Если в вашем файле 10 000 строк, программа сделает 10 000 отдельных обращений к SQL-серверу. Это крайне неэффективно и может «положить» сервер при большом объеме данных. Проанализируем, как сделать загрузку быстрее.
Правильный подход заключается в следующем: сначала мы считываем весь XML-файл в Таблицу Значений, а затем передаем эту таблицу в запрос в качестве параметра. Это позволит найти все необходимые документы одним махом. Рассмотрим шаги реализации:
Цена, Количество, Дата.ЧтениеXML.Согласно условию задачи, если у документа есть основание, оценка должна записываться и в основной документ, и в документ-основание. Важно помнить, что нельзя изменить данные документа-основания просто через точку: Объект.ДокументОснование.Качество = Оценка — это приведет к ошибке или отсутствию результата, так как через точку доступна только ссылка на объект, а не сам объект для редактирования.
Выясним, как сделать это правильно:
Если ЗначениеЗаполнено(Выборка.ДокументОснование) Тогда
ОбъектОснование = Выборка.ДокументОснование.ПолучитьОбъект();
ОбъектОснование.Качество = Оценка;
Попытка
ОбъектОснование.Записать();
Исключение
Сообщить("Не удалось записать документ-основание");
КонецПопытки;
КонецЕсли;
Проанализируем условие ПоступлениеТовара.Дата = &DATE. В 1С дата содержит время до секунды. Если в XML указана дата без времени или время отличается хотя бы на секунду, документ не будет найден. Чтобы избежать этого, рекомендуется использовать функцию НАЧАЛОПЕРИОДА в запросе или искать документы в интервале времени.
Также обратим внимание на сравнение чисел (Цена и Количество). В запросах SQL сравнение дробных чисел может работать нестабильно из-за особенностей хранения точности. Если вы сталкиваетесь с тем, что документ «не находится», попробуйте использовать в запросе условие МЕЖДУ с небольшой погрешностью или убедитесь, что типы данных в параметрах запроса и в базе данных идентичны.
В коде автора используется свойство ОбменДанными.Загрузка = Истина. Рассмотрим, на что это влияет. Данный флаг отключает большинство проверок в модуле объекта и подписках на события. Это значительно ускоряет запись, но будьте осторожны: если изменение поля «Качество» должно влечь за собой пересчет каких-то итогов или движений по регистрам, при включенном режиме Загрузка эти действия не выполнятся. Используйте этот режим только в тех случаях, когда вы уверены, что дополнительные проверки не нужны.
Разберем краткий чек-лист для подобных задач:
НачатьТранзакцию приходилось ЗафиксироватьТранзакцию в той же логической ветке.Продолжить, иначе вся обработка прервется на первой же ошибке.ЧтениеXML обязательно вызывайте Чтение.Закрыть(), чтобы файл не оставался заблокированным в системе.Объект.Записать() и проверьте, заходит ли туда код и не вылетает ли он в блок Исключение.Соблюдение этих правил позволит вам создавать надежные и быстрые механизмы интеграции 1С с внешними системами.