Как выгрузить регистр сведений в 1С:Конвертация данных 2.1 при переопределении типов документов?

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

При переносе данных между разнородными конфигурациями 1С с помощью «1С:Конвертация данных 2.1» (КД 2.1) разработчики часто сталкиваются со сложными сценариями — для этого есть перенос документов и остатков через КД 2.1. Один из таких сценариев — выгрузка записей независимого регистра сведений, измерения которого ссылаются на документы разных типов. Ситуация усложняется, если эти документы в правилах обмена уже переопределены (сопоставлены с другими типами объектов в базе-приемнике) и стандартная автоматическая конвертация типов в правилах конвертации свойств (ПКС) не срабатывает или заблокирована для редактирования.

В этой статье мы подробно разберем, почему стандартные подходы могут приводить к ошибкам и аварийному завершению работы платформы, как правильно настроить динамическое сопоставление правил конвертации объектов (ПКО) в ПКС, а также рассмотрим альтернативный, более надежный способ выгрузки регистров сведений с помощью встроенного языка.

Почему происходит сбой сеанса при использовании метода ВыгрузитьПоПравилу()?

При попытке решить задачу выгрузки связанных объектов «в лоб» разработчики часто обращаются к процедуре ВыгрузитьПоПравилу(). Однако вызов этого метода в обработчиках событий ПКО или ПКС (например, в событии «Перед выгрузкой» или «При выгрузке») для связанных документов может привести к аварийному завершению сеанса 1С (платформа просто закрывается без вывода понятных ошибок).

Выясним причину такого поведения. Это классическая проблема **бесконечной рекурсии и переполнения стека** (Stack Overflow) встроенного языка. Когда система пытается выгрузить документ-источник, она анализирует его движения или связанные записи регистра. Если внутри обработчиков регистра снова вызывается принудительная выгрузка этого же документа через ВыгрузитьПоПравилу() без жесткого контроля ссылок и отключения повторной выгрузки, платформа уходит в замкнутый цикл:

  1. Выгружается документ.
  2. Инициируется выгрузка записи регистра.
  3. Обработчик регистра вызывает выгрузку документа.
  4. Система возвращается к шагу 1 и так далее, пока не закончится оперативная память, выделенная под стек вызовов.

Поэтому использовать прямой вызов ВыгрузитьПоПравилу() внутри ПКС или ПКО связанных объектов крайне не рекомендуется, если вы детально не управляете кэшем выгруженных объектов и структурой входящих параметров.

Способ 1. Динамическое переопределение ИмяПКО в правиле конвертации свойства (ПКС)

Если для измерения регистра (например, «Документ») задан составной тип данных, и в базе-приемнике эти документы преобразуются в совершенно другие типы по уникальным правилам, нам необходимо подсказать системе, какое именно ПКО использовать в каждом конкретном случае.

В КД 2.1 для этого предусмотрен стандартный механизм динамической подмены имени ПКО — для этого подойдёт правила конвертации для миграции между конфигурациями. Мы можем управлять этим процессом с помощью предопределенного параметра ИмяПКО в обработчике события **«Перед выгрузкой»** конкретного ПКС.

Разберем по шагам, как это реализовать:

  1. Откройте ваше правило конвертации объектов (ПКО) для регистра сведений — есть настройка обмена данными по правилам конвертации объектов.
  2. Перейдите на вкладку «Правила конвертации свойств» (ПКС).
  3. Найдите свойство-измерение (например, «Документ-источник»), тип которого необходимо динамически сопоставлять.
  4. Откройте свойства этого ПКС и перейдите в обработчик события «Перед выгрузкой».
  5. Напишите код, который анализирует тип текущего источника и присваивает параметру ИмяПКО строковое имя соответствующего правила.

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


Если ЗначениеЗаполнено(Источник) Тогда
    ТипИсточника = ТипЗнч(Источник);
    
    Если ТипИсточника = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
        ИмяПКО = "РеализацияТоваровУслуг_Приемник";
        
    ИначеЕсли ТипИсточника = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда
        ИмяПКО = "ПеремещениеТоваров_Приемник";
        
    ИначеЕсли ТипИсточника = Тип("ДокументСсылка.ОтчетОРозничныхПродажах") Тогда
        ИмяПКО = "РозничныеПродажи_Приемник";
        
    КонецЕсли;
КонецЕсли;

Важный нюанс: Обязательно проверяйте значение на заполненность с помощью ЗначениеЗаполнено(Источник). Если этого не сделать, при попытке получить тип от пустой ссылки выгрузка завершится с ошибкой. Также явное указание ИмяПКО требуется только тогда, когда у вас для одного источника создано несколько разных ПКО (например, разные правила для обычного и упрощенного учета) или когда типы источника и приемника кардинально не совпадают. Если для типа существует ровно одно уникальное ПКО, КД 2.1 сопоставит его автоматически — есть готовые готовые правила для миграции данных между конфигурациями.

Особенности выгрузки независимых регистров сведений в КД 2.1

При настройке обмена для независимых регистров сведений важно понимать физику процесса их записи в базу-приемник. Платформа 1С:Предприятие записывает данные в регистры сведений не построчно, а наборами записей. Даже если вы переносите одну строку, система формирует и передает в XML-файл полноценный набор с установленным отбором по измерениям.

С этим связана одна из самых частых логических ошибок при разработке правил:

Если в ПКО регистра сведений в обработчике «Перед выгрузкой» вы пропишете условие фильтрации данных и установите параметр Отказ = Истина для определенных строк, КД 2.1 все равно создаст в результирующем файле узел набора записей. Но этот узел окажется пустым. При чтении файла в базе-приемнике пустой набор записей по данному отбору будет записан в регистр, что приведет к **полному затиранию (очистке) существующих данных** в приемнике по этому отбору! Чтобы этого избежать, фильтрацию записей регистра необходимо переносить на уровень выборки данных.

Способ 2. Альтернативный вариант с использованием функции ВыгрузитьРегистр()

Чтобы полностью обезопасить себя от бесконечной рекурсии, обойти ограничения составных типов и исключить риск случайной очистки данных в приемнике, мы рекомендуем использовать специализированную функцию КД 2.1 — ВыгрузитьРегистр().

Этот метод используется в Правилах выгрузки данных (ПВД) при установленном режиме выгрузки «Произвольный алгоритм». Мы полностью отказываемся от стандартной выборки платформы и берем управление процессом в свои руки.

Рассмотрим по шагам реализацию данного подхода:

  1. Создайте новое ПВД для вашего регистра сведений — поможет решение для переноса документов и справочников через КД 2.
  2. Установите способ выборки данных в значение «Произвольный алгоритм».
  3. В обработчике события «Перед обработкой» напишите запрос для получения нужных записей регистра сведений. В запросе вы можете сразу соединить таблицы, проверить типы документов, отсечь ненужные движения и отфильтровать пустые значения.
  4. Выгрузите результат запроса в таблицу значений.
  5. Сформируйте структуру отбора и вызовите функцию ВыгрузитьРегистр().

Посмотрим на пример практической реализации данного алгоритма:


// 1. Создаем запрос для получения данных из независимого регистра
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РегистрИсточник.Период КАК Период,
    |	РегистрИсточник.Документ КАК Документ,
    |	РегистрИсточник.Статус КАК Статус,
    |	РегистрИсточник.Сумма КАК Сумма
    |ИЗ
    |	РегистрСведений.СведенияОДокументах КАК РегистрИсточник
    |ГДЕ
    |	РегистрИсточник.Период >= &НачалоПериода";

Запрос.УстановитьПараметр("НачалоПериода", ДатаНачала);
ТаблицаДвижений = Запрос.Выполнить().Выгрузить();

// 2. Обходим таблицу и подготавливаем данные для выгрузки наборами
Для Каждого СтрокаДанных Из ТаблицаДвижений Цикл
    
    // Формируем структуру набора записей для КД
    НаборЗаписей = Новый Структура("Отбор, Строки");
    
    // Указываем отбор, по которому будет осуществляться запись в приемнике
    Отбор = Новый Структура;
    Отбор.Вставить("Документ", СтрокаДанных.Документ);
    НаборЗаписей.Отбор = Отбор;
    
    // Создаем таблицу строк для этого набора
    ТЗСтрок = ТаблицаДвижений.СкопироватьКолонки();
    ЗаполнитьЗначенияСвойств(ТЗСтрок.Добавить(), СтрокаДанных);
    НаборЗаписей.Строки = ТЗСтрок;
    
    // Вызываем системную процедуру выгрузки регистра
    ВыгрузитьРегистр(НаборЗаписей, , , , "ИмяРегистраПриемника");
    
КонецЦикла;

Этот подход обладает рядом ключевых преимуществ перед стандартной выгрузкой через ПКО:

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

← На главную