При загрузке или пакетной обработке данных из внешних источников (например, таблиц Excel) часто возникает типовая задача: проанализировать входящую строку, найти соответствующий элемент в информационной базе и создать документ только в том случае, если объект найден и прошел все проверки. Начинающие разработчики нередко сталкиваются с путаницей в логике: создав объект в памяти заранее, они пытаются найти способ «отменить» или «отсеять» документ при невыполнении условий.
Разберем детально, как устроен жизненный цикл объектов в платформе 1С:Предприятие, почему для отмены записи не требуются специальные директивы и как правильно структурировать алгоритм обработки.
Вызов метода СоздатьДокумент() менеджера документов создает экземпляр объекта исключительно в оперативной памяти приложения. На этом этапе никаких изменений в базе данных СУБД не происходит. Физическая вставка строк в таблицы базы данных выполняется строго в момент вызова метода Записать().
Рассмотрим важные следствия этого механизма:
Записать() не вызывается, документ никогда не попадет в базу данных. «Удалять» или специально «отменять» его не нужно — платформа автоматически очистит память через сборщик мусора при выходе из процедуры или на следующей итерации цикла.Отказ, с помощью которого отменяется запись, существует только внутри предопределенных обработчиков событий (например, ПередЗаписью(Отказ, РежимЗаписи)). В произвольном коде обработок или модулей переменной Отказ нет, а логика ветвления управляется стандартными операторами Если ... Тогда, Продолжить или Возврат.ОбработкаЗаполнения) и выделяет системные ресурсы. Вызывать СоздатьДокумент() до того, как проверены базовые условия (например, наличие элемента справочника), является избыточным действием.Посмотрим на классическую реализацию пакетной загрузки в цикле. Если при поиске основного средства по инвентарному номеру ссылка не найдена, мы фиксируем информацию об ошибке и немедленно переходим к следующей строке с помощью оператора Продолжить. Создание самого документа переносится строго после всех проверок.
Для Каждого СтрокаДанных Из ТаблицаЗагрузки Цикл
// 1. Ищем элемент справочника
ОсновноеСредство = Справочники.ОсновныеСредства.НайтиПоРеквизиту("ИнвентарныйНомер", СтрокаДанных.ИнвентарныйНомер);
// 2. Проверяем, найден ли элемент
Если Не ЗначениеЗаполнено(ОсновноеСредство) Тогда
Сообщить("Основное средство с инвентарным номером " + СтрокаДанных.ИнвентарныйНомер + " не найдено. Пропуск строки.");
Продолжить;
КонецЕсли;
// 3. Дополнительная валидация данных
Если ОсновноеСредство.Наименование <> Лев(СтрокаДанных.Наименование, 80) Тогда
Сообщить("Расхождение в наименовании для инвентарного номера " + СтрокаДанных.ИнвентарныйНомер);
Продолжить;
КонецЕсли;
// 4. Создаем и записываем документ только при успешном прохождении проверок
ДокОС = Документы.ОС_ВводИсторииПереоценки.СоздатьДокумент();
ДокОС.Дата = ТекущаяДата();
ДокОС.Учреждение = СсылкаНаУчреждение;
ДокОС.ОС = ОсновноеСредство;
ДокОС.Записать(РежимЗаписиДокумента.Запись);
КонецЦикла;
В этом примере документ даже не инициализируется в памяти, если инвентарный номер не найден, что существенно экономит ресурсы сервера и исключает случайную запись некорректных данных.
Если структура цикла требует обязательного выполнения завершающих действий на каждой итерации (например, проставления статусов обработки строк во внешнем файле), воспользуемся явным ветвлением.
ОсновноеСредство = Справочники.ОсновныеСредства.НайтиПоРеквизиту("ИнвентарныйНомер", тИнвентарныйНомер);
Если ОсновноеСредство.Пустая() Тогда
// Объект не найден: пишем в лог, документ не создаем и не записываем
Сообщить("Не найдено ОС: " + тИнвентарныйНомер);
ExcelЛист.Cells(Row, 19).Value = "Не найден";
Иначе
// Объект найден: создаем документ, заполняем реквизиты и сохраняем
ДокОС = Документы.ОС_ВводИсторииПереоценки.СоздатьДокумент();
ДокОС.Дата = ТекущаяДата();
ДокОС.Учреждение = спрУчрж;
ДокОС.ОС = ОсновноеСредство;
ДокОС.Записать(РежимЗаписиДокумента.Запись);
ExcelЛист.Cells(Row, 19).Value = "Успешно";
КонецЕсли;
Разберем технические нюансы, которые необходимо учитывать при реализации подобных загрузок:
основн = спрОС.ПустаяСсылка() требует наличия инициализированного менеджера справочника. Надежнее использовать метод самой ссылки ОсновноеСредство.Пустая() либо системную функцию Не ЗначениеЗаполнено(ОсновноеСредство), которая корректно обрабатывает пустые ссылки, Неопределено и Null.НайтиПоРеквизиту() внутри цикла обращается к базе данных отдельным запросом на каждом шаге. Если строк много, это приведет к просадке производительности. Кроме того, поиск работает быстро только при включенном свойстве реквизита «Индексировать». Для обработки больших массивов данных эффективнее предварительно загрузить все номера в массив и выбрать существующие элементы одним запросом с помощью конструкции В (&МассивНомеров).Excel.SaveAs()) работают крайне медленно из-за межпроцессного взаимодействия и дисковых операций ввода-вывода. Сохранение файла Excel следует выполнять один раз — после полного завершения цикла обработки строк, а не на каждой итерации при возникновении ошибки.