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