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