Как сопоставить данные из Excel со справочником Номенклатура и обновить реквизиты в 1С 8.3

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

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

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

Анализ типичных ошибок при загрузке данных

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


&НаКлиенте
Процедура Объединить(Команда)
    Для Каждого Стр Из Объект.ДанныеПоискаИзExcel Цикл
        Сравнение = Сравнение.Сравнить(Объект.Артикул, Объект.ДанныеПоискаИзExcel.Артикул);
        // Ошибка: попытка обращения к реквизиту всей таблицы вместо текущей строки,
        // а также попытка прочитать данные базы данных напрямую на клиенте
    КонецЦикла;
КонецПроцедуры

Проанализируем основные проблемы данного подхода:

  1. Выполнение тяжелых операций на клиенте: поиск и сопоставление данных базы должны выполняться исключительно на сервере. Клиентский контекст не имеет прямого доступа к таблицам базы данных без серверных вызовов.
  2. Неправильное обращение к строкам таблицы: внутри цикла Для Каждого Стр Из ... обращаться к значениям текущей строки необходимо через переменную итератора (Стр.Артикул), а не через всю коллекцию (Объект.ДанныеПоискаИзExcel.Артикул).
  3. Использование некорректных типов и конструкций: прямое сравнение объектов в цикле без использования запросов приводит к высокой нагрузке и неоптимальной производительности при больших объемах данных.

Правильный алгоритм решения задачи на сервере

Оптимальная архитектура загрузки строится по следующей схеме:

  1. Прочитать данные из файла Excel во временную структуру — объект ТаблицаЗначений.
  2. Передать сформированную таблицу значений в качестве параметра в запрос на сервере.
  3. В запросе поместить данные во временную таблицу и выполнить ЛЕВОЕ СОЕДИНЕНИЕ со справочником Номенклатура по ключевым полям поиска.
  4. Обойти выборку результата запроса, получить объект каждого найденного элемента через ПолучитьОбъект(), заполнить целевые реквизиты и записать изменения.

Реализация загрузки и сопоставления с помощью запроса

Разберем по шагам серверную процедуру обновления данных номенклатуры. Посмотрим на пример программного кода:


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

КонецПроцедуры

Связывание серверной логики с интерфейсом формы

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


&НаКлиенте
Процедура ВыполнитьСопоставление(Команда)
    // Вызываем серверный метод обработки данных
    ЗапуститьОбновлениеНаСервере();
    ПоказатьОповещениеПользователя("Успешно", , "Данные номенклатуры успешно обновлены!");
КонецПроцедуры

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

Важные практические нюансы при загрузке

Рассмотрим подробнее важные моменты, которые необходимо учитывать при работе со строками и запросами:

  1. Типизация колонок таблицы: если ТаблицаЗначений формируется программно «с нуля», для всех колонок обязательно должно быть задано ОписаниеТипов. Если передать в запрос таблицу с нетипизированными колонками, платформа вызовет ошибку соединения типов.
  2. Очистка строк: строковые значения из Excel часто содержат неразрывные пробелы (код 160) и лишние пробелы по краям. Перед загрузкой рекомендуется очищать строковые поля через СокрЛП(СтрЗаменить(Строка, Символы.НПП, " ")).
  3. Ссылочные поля: если реквизит Производитель в справочнике Номенклатура имеет тип ссылки (а не строки), в условии соединения запроса следует обращаться к полю наименования ссылки: СпрНоменклатура.Производитель.Наименование = ВТ_Excel.Производитель.
  4. Флаг загрузки: установка свойства ОбъектНоменклатуры.ОбменДанными.Загрузка = Истина позволяет отключить избыточные обработчики событий и проверки при записи, что существенно ускоряет обработку прайс-листов.
← На главную