Как правильно загрузить номенклатуру со ссылочными реквизитами из файла в 1С?

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

При переносе данных справочника номенклатуры из одной информационной базы 1С в другую с использованием текстового файла (CSV/TXT) начинающие разработчики часто сталкиваются со следующей проблемой: примитивные типы данных (код, наименование, артикул) переносятся корректно, а реквизиты ссылочного типа (единица измерения, вид номенклатуры, ставка НДС, группа) остаются пустыми.

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

В чем разница между примитивными и ссылочными типами данных?

Для понимания логики работы алгоритмов загрузки важно четко разделять типы данных реквизитов объектов 1С:

  1. Примитивные типы (Строка, Число, Булево, Дата) — хранятся непосредственно в поле таблицы объекта. При считывании текста из файла значение текстовой строки можно сразу напрямую присвоить реквизиту Код или Наименование.
  2. Ссылочные типы — значением реквизита является не сама строка (например, "шт" или "Товары"), а уникальная ссылка на элемент другого справочника (Справочники.БазовыеЕдиницыИзмерения, Справочники.ВидыНоменклатуры) или на значение перечисления (Перечисления.СтавкиНДС).

Если мы попытаемся присвоить ссылочному реквизиту текстовую строку из файла (например, Спр.ВидНоменклатуры = "Товар"), платформа либо проигнорирует запись, либо выдаст ошибку несоответствия типов. Чтобы реквизит заполнялся корректно, нам необходимо сначала найти объект в базе по коду или наименованию (или создать новый), получить его ссылку и только потом записать ее в реквизит номенклатуры.

Выгрузка данных из исходной базы

Рассмотрим стандартный механизм текстовой выгрузки элементов справочника номенклатуры. Формируем текстовый документ, где значение каждого реквизита разделяется специальным символом, например точка с запятой (;).

Пример кода выгрузки справочника в текстовый файл:


Процедура КнопкаВыгрузитьНажатие(Кнопка)
    Текст = Новый ТекстовыйДокумент;
    Выборка = Справочники.Номенклатура.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        // Формируем строку с разделителями
        СтрокаДанных = Выборка.Код + ";" + 
                       Выборка.Наименование + ";" + 
                       Выборка.Родитель + ";" + 
                       Выборка.ВидНоменклатуры + ";" + 
                       Выборка.БазоваяЕдиницаИзмерения + ";" +
                       Выборка.СтавкаНДС;
                       
        Текст.ДобавитьСтроку(СтрокаДанных);
    КонецЦикла;
    
    Текст.Записать("d:\test\test.txt");
КонецПроцедуры

Загрузка элементов и поиск ссылочных реквизитов

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

Разберем способы сопоставления ссылок для разных типов реквизитов:

  1. Заполнение единицы измерения и вида номенклатуры: выполняем поиск элемента в целевой базе с помощью метода НайтиПоНаименованию() или НайтиПоКоду().
  2. Заполнение перечислений (Ставка НДС): перечисления являются предопределенными значениями, их нельзя создать из кода. Для их подстановки анализируем входящий текст и возвращаем конкретное значение структуры Перечисления.СтавкиНДС.

Функция для определения значения перечисления ставки НДС:


Функция НайтиСтавкуНДСПоСтроке(ВходящаяСтрока)
    ТекстСтроки = НРег(СокрЛП(ВходящаяСтрока));
    
    Если Найти(ТекстСтроки, "без") > 0 Тогда
        Возврат Перечисления.СтавкиНДС.БезНДС;
    ИначеЕсли Найти(ТекстСтроки, "18") > 0 Тогда
        Возврат Перечисления.СтавкиНДС.НДС18;
    ИначеЕсли Найти(ТекстСтроки, "10") > 0 Тогда
        Возврат Перечисления.СтавкиНДС.НДС10;
    Иначе
        Возврат Перечисления.СтавкиНДС.НДС0;
    КонецЕсли;
КонецФункции

Теперь объединим эти шаги в итоговую процедуру загрузки номенклатуры:


Процедура ЗагрузитьНоменклатуруИзФайла()
    Текст = Новый ТекстовыйДокумент;
    Текст.Прочитать("d:\test\test.txt");
    
    Для НомерСтроки = 1 По Текст.КоличествоСтрок() Цикл
        Стр = Текст.ПолучитьСтроку(НомерСтроки);
        МассивСтрок = РазложитьСтрокуВМассивПодстрок(Стр, ";");
        
        Спр = Справочники.Номенклатура.СоздатьЭлемент();
        
        // Заполнение примитивных реквизитов
        Спр.Код = МассивСтрок[0];
        Спр.Наименование = МассивСтрок[1];
        
        // Поиск ссылок в соответствующих справочниках
        Спр.ВидНоменклатуры = Справочники.ВидыНоменклатуры.НайтиПоНаименованию(МассивСтрок[3]);
        Спр.ЕдиницаИзмерения = Справочники.БазовыеЕдиницыИзмерения.НайтиПоНаименованию(МассивСтрок[4]);
        
        // Заполнение значения перечисления
        Спр.СтавкаНДС = НайтиСтавкуНДСПоСтроке(МассивСтрок[5]);
        
        Спр.Записать();
    КонецЦикла;
КонецПроцедуры

Обработка иерархии и группы (Родитель)

Если в целевой базе необходимо сохранять иерархическую структуру (папки и группы), простая запись текстового имени группы в реквизит Родитель работать не будет. Требуется сначала найти или создать группу справочника.

Для работы с группами применяется отдельный метод создания — СоздатьГруппу():


Функция ПолучитьСсылкуНаГруппу(НаименованиеГруппы, ТекущийРодитель = Неопределено)
    НайденнаяГруппа = Справочники.Номенклатура.НайтиПоНаименованию(НаименованиеГруппы, Истина);
    
    Если НайденнаяГруппа.Пустая() Тогда
        ОбъектГруппа = Справочники.Номенклатура.СоздатьГруппу();
        ОбъектГруппа.Наименование = СокрЛП(НаименованиеГруппы);
        Если ТекущийРодитель <> Неопределено Тогда
            ОбъектГруппа.Родитель = ТекущийРодитель;
        КонецЕсли;
        ОбъектГруппа.Записать();
        Возврат ОбъектГруппа.Ссылка;
    Иначе
        Возврат НайденнаяГруппа;
    КонецЕсли;
КонецФункции

Оптимизация загрузки больших объемов данных

Если вам требуется загрузить масштабную базу (например, от 10 000 до 200 000 позиций), стандартный поэлементный подход вызовет существенное падение производительности. Для ускорения процесса рекомендуется соблюдать следующие правила:

  1. Использование транзакций: запись элементов по одному производит постоянное обращение к диску. Оборачивайте порции элементов (по 1000–5000 штук) в блоки НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Это ускорит загрузку в десятки раз.
  2. Флаг загрузки данных: перед записью объекта устанавливайте Спр.ОбменДанными.Загрузка = Истина. Это отключает лишние тяжелые проверки модуля объекта и бизнес-логику конфигурации.
  3. Кэширование данных: постоянный поиск через НайтиПоНаименованию() на каждой итерации цикла отправляет запросы к СУБД. Рекомендуется один раз перед запуском цикла сопоставить виды номенклатуры и единицы измерения, сохранив ссылки в объект Соответствие или Структура.
← На главную