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