При разработке обработок загрузки прайс-листов и каталогов товаров из внешних файлов Excel часто возникает задача: сопоставить строки файла с существующими элементами в базе данных по ключевым реквизитам (например, по комбинации «Артикул» и «Производитель») и дозаполнить недостающую информацию (описание, ссылки на изображения, свойства).
Разберем типичные ошибки начинающих разработчиков при попытке выполнить эту операцию на клиенте и рассмотрим правильный, производительный алгоритм сопоставления и обновления объектов на стороне сервера.
Выясним причину возникновения ошибки Поле объекта не обнаружено (Артикул), с которой часто сталкиваются новички. Рассмотрим исходный ошибочный фрагмент кода:
&НаКлиенте
Процедура Объединить(Команда)
Для Каждого Стр Из Объект.ДанныеПоискаИзExcel Цикл
Сравнение = Сравнение.Сравнить(Объект.Артикул, Объект.ДанныеПоискаИзExcel.Артикул);
// Ошибка: попытка обращения к реквизиту всей таблицы вместо текущей строки,
// а также попытка прочитать данные базы данных напрямую на клиенте
КонецЦикла;
КонецПроцедуры
Проанализируем основные проблемы данного подхода:
Для Каждого Стр Из ... обращаться к значениям текущей строки необходимо через переменную итератора (Стр.Артикул), а не через всю коллекцию (Объект.ДанныеПоискаИзExcel.Артикул).Оптимальная архитектура загрузки строится по следующей схеме:
ТаблицаЗначений.ЛЕВОЕ СОЕДИНЕНИЕ со справочником Номенклатура по ключевым полям поиска.ПолучитьОбъект(), заполнить целевые реквизиты и записать изменения.Разберем по шагам серверную процедуру обновления данных номенклатуры. Посмотрим на пример программного кода:
&НаСервере
Процедура ОбновитьНоменклатуруИзТаблицыНаСервере(ТаблицаДанных)
// Подготавливаем запрос с временной таблицей
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Данные.Артикул КАК Артикул,
| ВТ_Данные.Производитель КАК Производитель,
| ВТ_Данные.Описание КАК Описание,
| ВТ_Данные.СсылкаНаКартинку КАК СсылкаНаКартинку
|ПОМЕСТИТЬ ВТ_Excel
|ИЗ
| &ТаблицаДанных КАК ВТ_Данные
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| СпрНоменклатура.Ссылка КАК Ссылка,
| ВТ_Excel.Описание КАК ОписаниеТовара,
| ВТ_Excel.СсылкаНаКартинку КАК ПутьККартинке
|ИЗ
| ВТ_Excel КАК ВТ_Excel
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
| ПО (СпрНоменклатура.Артикул = ВТ_Excel.Артикул)
| И (СпрНоменклатура.Производитель.Наименование = ВТ_Excel.Производитель)
|ГДЕ
| НЕ СпрНоменклатура.ПометкаУдаления";
Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем объект номенклатуры для изменения
ОбъектНоменклатуры = Выборка.Ссылка.ПолучитьОбъект();
Если ОбъектНоменклатуры <> Неопределено Тогда
ОбъектНоменклатуры.Описание = Выборка.ОписаниеТовара;
ОбъектНоменклатуры._ПутьКартинкамНаСайте = Выборка.ПутьККартинке;
// Отключаем лишние платформенные проверки для ускорения записи
ОбъектНоменклатуры.ОбменДанными.Загрузка = Истина;
Попытка
ОбъектНоменклатуры.Записать();
Исключение
// Обработка ошибок записи конкретного элемента
ЗаписьЖурналаРегистрации("ЗагрузкаИзExcel", УровеньЖурналаРегистрации.Ошибка,,,
"Ошибка записи элемента: " + Выборка.Ссылка + " — " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Рассмотрим, как связать обработку нажатия кнопки на форме с серверной процедурой. В контексте управляемой формы табличная часть формы выгружается в отдельную таблицу значений перед передачей в запрос:
&НаКлиенте
Процедура ВыполнитьСопоставление(Команда)
// Вызываем серверный метод обработки данных
ЗапуститьОбновлениеНаСервере();
ПоказатьОповещениеПользователя("Успешно", , "Данные номенклатуры успешно обновлены!");
КонецПроцедуры
&НаСервере
Процедура ЗапуститьОбновлениеНаСервере()
// Преобразуем данные формы в обычную таблицу значений
ТаблицаДляЗапроса = Объект.ДанныеПоискаИзExcel.Выгрузить();
// Передаем таблицу в процедуру обновления
ОбновитьНоменклатуруИзТаблицыНаСервере(ТаблицаДляЗапроса);
КонецПроцедуры
Рассмотрим подробнее важные моменты, которые необходимо учитывать при работе со строками и запросами:
ТаблицаЗначений формируется программно «с нуля», для всех колонок обязательно должно быть задано ОписаниеТипов. Если передать в запрос таблицу с нетипизированными колонками, платформа вызовет ошибку соединения типов.СокрЛП(СтрЗаменить(Строка, Символы.НПП, " ")).Производитель в справочнике Номенклатура имеет тип ссылки (а не строки), в условии соединения запроса следует обращаться к полю наименования ссылки: СпрНоменклатура.Производитель.Наименование = ВТ_Excel.Производитель.ОбъектНоменклатуры.ОбменДанными.Загрузка = Истина позволяет отключить избыточные обработчики событий и проверки при записи, что существенно ускоряет обработку прайс-листов.