В процессе разработки часто возникает задача автоматизации ввода данных, например, загрузка перечня материалов для определенных работ из файла Excel. Несмотря на кажущуюся простоту, программисты (особенно начинающие) часто сталкиваются с тем, что данные «не сохраняются», табличная часть остается пустой или система выдает ошибки при попытке записи. В этой статье мы подробно разберем, как правильно организовать код для добавления строк в табличную часть справочника, и проанализируем основные подводные камни.
Рассмотрим ситуацию: у нас есть справочник ИмпРаботы, в котором имеется табличная часть Материалы. Нам нужно найти существующую работу по наименованию (или создать новую) и добавить в её табличную часть строки с номенклатурой, количеством и ценой, взятыми из табличного документа (результат чтения Excel).
Разберем основные ошибки, которые могут встретиться на пути:
Записать() не сработает, если они пусты. Это заблокирует и сохранение табличной части.Если справочник уже существует в базе, нам сначала нужно найти его, получить объект для редактирования, внести изменения и записать. Проанализируем правильную структуру кода:
// 1. Находим ссылку на нужный элемент справочника
СсылкаНаРаботу = Справочники.ИмпРаботы.НайтиПоНаименованию(НаименованиеИзФайла);
Если Не СсылкаНаРаботу.Пустая() Тогда
// 2. Получаем объект из ссылки для возможности редактирования
ОбъектРаботы = СсылкаНаРаботу.ПолучитьОбъект();
// 3. Добавляем новую строку в табличную часть "Материалы"
НоваяСтрока = ОбъектРаботы.Материалы.Добавить();
// 4. Заполняем реквизиты строки
НоваяСтрока.Материал = Справочники.Номенклатура.НайтиПоНаименованию(ИмяМатериала);
// Важно: преобразуем текст из ячейки в числовое значение
Попытка
НоваяСтрока.Количество = Число(ТекстКоличества);
НоваяСтрока.ЦенаМатериала = Число(ТекстЦены);
Исключение
НоваяСтрока.Количество = 0;
Сообщить("Ошибка преобразования числа в строке " + НомерСтроки);
КонецПопытки;
// 5. Записываем изменения в базу данных
Попытка
ОбъектРаботы.Записать();
Исключение
Сообщить("Не удалось записать объект: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЕсли;
Рассмотрим ситуацию, когда мы создаем новый элемент справочника «на лету». В этом случае нам не нужно использовать метод ПолучитьОбъект(), так как метод СоздатьЭлемент() сразу возвращает объектную сущность.
Проанализируем пример совместной работы с основными реквизитами и табличной частью:
НовыйСпр = Справочники.ИмпРаботы.СоздатьЭлемент();
НовыйСпр.Наименование = "Монтажные работы";
НовыйСпр.ЕдиницаОбъема = Справочники.ИмпЕдиницыИзмерения.НайтиПоНаименованию("м2");
// Обязательно заполняем системные или бизнес-реквизиты, без которых запись невозможна
НовыйСпр.Продолжительность = 8;
НовыйСпр.ЧасыРаботы = 160;
// Сразу добавляем материалы в новый (еще не записанный) объект
СтрМат = НовыйСпр.Материалы.Добавить();
СтрМат.Материал = Справочники.Номенклатура.НайтиПоНаименованию("Цемент");
СтрМат.Количество = 10;
// Записываем всё один раз в конце
НовыйСпр.Записать();
Выясним причину, с которой столкнулся автор темы. Иногда после выполнения кода программно добавленные строки исчезают. Рассмотрим основные причины:
ПередЗаписью: В модуле справочника может быть написан код, который очищает табличную часть при определенных условиях или проверяет заполнение других полей. Если проверка не пройдена (например, не заполнены «Часы работы»), база данных отклоняет транзакцию.ОбменДанными.Загрузка = Истина. Это позволит «обойти» некоторые проверки, которые могут мешать записи неполных данных.Рассмотрим, как сделать код более профессиональным. Использование НайтиПоНаименованию внутри цикла по 1000 строк — это плохая практика, так как программа будет делать 1000 отдельных запросов к базе.
Рекомендация по кэшированию: Перед началом загрузки выгрузите всю нужную номенклатуру в объект Соответствие, где ключом будет наименование, а значением — ссылка. Это ускорит поиск в десятки раз.
Использование транзакций: Чтобы загрузка была атомарной (либо загрузилось всё, либо ничего в случае ошибки), оберните цикл загрузки в транзакцию:
НачатьТранзакцию();
Попытка
// Цикл загрузки данных
// ... ваш код добавления строк ...
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Загрузка прервана из-за критической ошибки!");
КонецПопытки;
При чтении данных из ТабличногоДокумента (который часто получается после ПостроительЗапроса или загрузки Excel), важно правильно обращаться к ячейкам. Вместо использования ТекущаяОбласть.Текст, что всегда возвращает строку, лучше проверять свойство СодержитЗначение. Это поможет избежать проблем с форматами дат и дробных чисел, если ячейки в Excel были правильно типизированы.
Подведем итог: для успешного добавления материалов в справочник «Работы» необходимо убедиться, что вы работаете с объектом (а не ссылкой), заполняете все обязательные реквизиты шапки и корректно приводите типы данных перед заполнением колонок табличной части.