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