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