Как программно добавить данные в табличную часть справочника при загрузке из внешнего источника

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

В процессе разработки часто возникает задача автоматизации ввода данных, например, загрузка перечня материалов для определенных работ из файла Excel. Несмотря на кажущуюся простоту, программисты (особенно начинающие) часто сталкиваются с тем, что данные «не сохраняются», табличная часть остается пустой или система выдает ошибки при попытке записи. В этой статье мы подробно разберем, как правильно организовать код для добавления строк в табличную часть справочника, и проанализируем основные подводные камни.

Анализ исходной задачи и типичные ошибки

Рассмотрим ситуацию: у нас есть справочник ИмпРаботы, в котором имеется табличная часть Материалы. Нам нужно найти существующую работу по наименованию (или создать новую) и добавить в её табличную часть строки с номенклатурой, количеством и ценой, взятыми из табличного документа (результат чтения Excel).

Разберем основные ошибки, которые могут встретиться на пути:

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

Вариант 1: Добавление данных в существующий справочник

Если справочник уже существует в базе, нам сначала нужно найти его, получить объект для редактирования, внести изменения и записать. Проанализируем правильную структуру кода:


// 1. Находим ссылку на нужный элемент справочника
СсылкаНаРаботу = Справочники.ИмпРаботы.НайтиПоНаименованию(НаименованиеИзФайла);

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

Вариант 2: Создание нового элемента с табличной частью

Рассмотрим ситуацию, когда мы создаем новый элемент справочника «на лету». В этом случае нам не нужно использовать метод ПолучитьОбъект(), так как метод СоздатьЭлемент() сразу возвращает объектную сущность.

Проанализируем пример совместной работы с основными реквизитами и табличной частью:


НовыйСпр = Справочники.ИмпРаботы.СоздатьЭлемент();
НовыйСпр.Наименование = "Монтажные работы";
НовыйСпр.ЕдиницаОбъема = Справочники.ИмпЕдиницыИзмерения.НайтиПоНаименованию("м2");

// Обязательно заполняем системные или бизнес-реквизиты, без которых запись невозможна
НовыйСпр.Продолжительность = 8; 
НовыйСпр.ЧасыРаботы = 160;

// Сразу добавляем материалы в новый (еще не записанный) объект
СтрМат = НовыйСпр.Материалы.Добавить();
СтрМат.Материал = Справочники.Номенклатура.НайтиПоНаименованию("Цемент");
СтрМат.Количество = 10;

// Записываем всё один раз в конце
НовыйСпр.Записать();

Почему данные могут «пропадать» при записи?

Выясним причину, с которой столкнулся автор темы. Иногда после выполнения кода программно добавленные строки исчезают. Рассмотрим основные причины:

Оптимизация: Поиск и Транзакции

Рассмотрим, как сделать код более профессиональным. Использование НайтиПоНаименованию внутри цикла по 1000 строк — это плохая практика, так как программа будет делать 1000 отдельных запросов к базе.

Рекомендация по кэшированию: Перед началом загрузки выгрузите всю нужную номенклатуру в объект Соответствие, где ключом будет наименование, а значением — ссылка. Это ускорит поиск в десятки раз.

Использование транзакций: Чтобы загрузка была атомарной (либо загрузилось всё, либо ничего в случае ошибки), оберните цикл загрузки в транзакцию:


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

Работа с Табличным Документом

При чтении данных из ТабличногоДокумента (который часто получается после ПостроительЗапроса или загрузки Excel), важно правильно обращаться к ячейкам. Вместо использования ТекущаяОбласть.Текст, что всегда возвращает строку, лучше проверять свойство СодержитЗначение. Это поможет избежать проблем с форматами дат и дробных чисел, если ячейки в Excel были правильно типизированы.

Подведем итог: для успешного добавления материалов в справочник «Работы» необходимо убедиться, что вы работаете с объектом (а не ссылкой), заполняете все обязательные реквизиты шапки и корректно приводите типы данных перед заполнением колонок табличной части.

← На главную