Как правильно загрузить данные из Excel в периодический регистр сведений 1С и избежать перезаписи строк

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

Загрузка данных из внешних файлов, таких как Excel, является одной из самых частых задач для разработчика 1С. Однако при работе с периодическими регистрами сведений начинающие программисты часто сталкиваются с ситуацией, когда вместо создания множества записей в базе остается только одна или несколько строк. Рассмотрим, почему это происходит и как реализовать загрузку правильно, эффективно и надежно.

Разбор типичной ошибки: почему данные пропадают?

Проанализируем ситуацию, представленную в вопросе. Автор пытался загрузить остатки товаров из Excel, используя МенеджерЗаписи внутри цикла. Главная проблема заключалась в следующем фрагменте кода:


Для Стр = 1 По ПоследняяСтрока Цикл
    Дата = '20130720000000';
    Дата = Дата + 1;
    // ... логика записи ...
КонецЦикла;

В чем здесь ошибка? Разберем по шагам. Переменная Дата инициализируется внутри цикла. Это означает, что на каждой итерации (для каждой строки Excel) дата сбрасывается к одному и тому же значению. Прибавление единицы (Дата + 1) в 1С добавляет к дате одну секунду. Таким образом, абсолютно все записи пытались записаться на одну и ту же секунду: 20.07.2013 00:00:01.

Поскольку регистр сведений является периодическим, его уникальность определяется комбинацией измерений и периода. Если мы записываем новую порцию данных с теми же измерениями (Номенклатура, Характеристика) и тем же периодом, система просто перезаписывает старую запись. Именно поэтому у автора «исчезали» строки — они накладывались друг на друга в одной точке времени.

Решение проблемы: правильная работа с периодом

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


&НаКлиенте
Процедура ЗагрузитьДанныеТабеля(Команда)
    Excel = Новый COMОбъект("Excel.Application");
    Книга = Excel.WorkBooks.Open("C:\1213.xlsx");
    ЛистДанных = Книга.Sheets(1);
    ПоследняяСтрока = ЛистДанных.UsedRange.Row + ЛистДанных.UsedRange.Rows.Count - 1;  
    
    // Инициализируем дату ОДИН РАЗ перед началом обработки файла
    ТекущаяДатаЗаписи = '20130720000000';
    
    Для Стр = 1 По ПоследняяСтрока Цикл
        // Увеличиваем время для каждой новой строки, если нам нужна уникальность по периоду
        ТекущаяДатаЗаписи = ТекущаяДатаЗаписи + 1; 
                
        Номенклатура = ЛистДанных.Cells(Стр, 1).Text;
        Характеристика = ЛистДанных.Cells(Стр, 2).Text;
        МаксОстаток = ЛистДанных.Cells(Стр, 3).Text;
                
        ДобавитьЗаписьТабеля(Номенклатура, Характеристика, МаксОстаток, ТекущаяДатаЗаписи);    
    КонецЦикла;
    
    Excel.Application.Quit();
    Excel = Неопределено; // Обязательно освобождаем память
КонецПроцедуры

Оптимизация: использование набора записей вместо менеджера

Использование РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи() внутри цикла — это крайне медленный способ. На каждой итерации программа обращается к базе данных, выполняет транзакцию записи и блокирует таблицу. Если в файле Excel 10 000 строк, процесс может затянуться надолго.

Проанализируем более эффективный подход — использование объекта НаборЗаписей. Это позволит записать все данные одним «пакетом». Рассмотрим, как это реализовать на сервере:


&НаСервере
Процедура ЗагрузитьНаборДанных(ТаблицаДанных)
    // Создаем набор записей
    Набор = РегистрыСведений.МаксОстатокПоТоварам.СоздатьНаборЗаписей();
    
    // Если нужно добавить данные к существующим, фильтры не ставим, 
    // но вызываем Набор.Прочитать() и затем добавляем новые.
    // Если нужно полностью заменить данные за период — используем отбор.
    
    Для Каждого СтрокаИзExcel Из ТаблицаДанных Цикл
        НоваяЗапись = Набор.Добавить();
        НоваяЗапись.Период = СтрокаИзExcel.Дата;
        НоваяЗапись.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию(СтрокаИзExcel.Номенклатура);
        НоваяЗапись.Характеристика = Справочники.ХарактеристикиНоменклатуры.НайтиПоНаименованию(СтрокаИзExcel.Характеристика);
        НоваяЗапись.МаксОстаток = СтрокаИзExcel.МаксОстаток;
    КонецЦикла;
    
    // Записываем всё одним махом. Параметр Ложь означает, что мы НЕ заменяем 
    // все записи в регистре, а только добавляем те, что в наборе.
    Набор.Записать(Ложь); 
КонецПроцедуры

Повышение надежности поиска объектов

В исходном примере используется метод НайтиПоНаименованию. Проанализируем риски этого метода:

  1. Дубликаты: Если в справочнике есть две «Модели 1», система выберет первую попавшуюся, что может привести к ошибкам учета.
  2. Лишние символы: Наличие невидимого пробела в Excel-ячейке приведет к тому, что НайтиПоНаименованию вернет пустую ссылку.

Выясним, как сделать поиск надежнее. Рекомендуется использовать поиск по уникальным идентификаторам: Коду или Артикулу. Также обязательно добавим проверку на «пустое» значение перед записью:


СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоКоду(КодИзExcel);
Если СсылкаНоменклатура.Пустая() Тогда
    Сообщить("Товар с кодом " + КодИзExcel + " не найден в базе!");
    Продолжить; // Пропускаем строку, чтобы не плодить битые данные
КонецЕсли;

Современный подход: чтение Excel без COM-объекта

Использование COMОбъект("Excel.Application") требует установленного Microsoft Office на компьютере пользователя и часто приводит к «зависанию» процессов в памяти. Проанализируем современный способ через ТабличныйДокумент, который работает быстрее и стабильнее:

  1. Используем метод Прочитать() для загрузки файла напрямую в объект 1С.
  2. Обходим ячейки таблицы 1С программно.

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

Итоги и рекомендации

Для успешной загрузки данных из Excel в регистры сведений 1С придерживаемся следующих правил:

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

← На главную