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