Почему теряется или визуально пропадает ссылка после записи десериализованного объекта в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке механизмов интеграции, обмена данными или мобильных приложений на платформе «1С:Предприятие» разработчики часто сталкиваются с нестандартным поведением платформы. Одна из таких загадочных проблем — визуальное «исчезновение» или «очистка» ссылки нового объекта справочника сразу после его записи в базу данных. В этой статье мы подробно разберем, почему возникает эта иллюзия, как устроен механизм формирования представлений в платформе 1С и как правильно локализовать и устранить данную ошибку.

Симптомы проблемы и анализ исходной ситуации

Рассмотрим сценарий программного переноса данных, с которым столкнулся автор темы. Из базы-источника в базу-приемник передается таблица значений, содержащая ссылки (уникальные идентификаторы) переносимых элементов. Алгоритм загрузки выглядит вполне стандартно и лаконично:


Элемент = Справочники[ИмяМетаданных].СоздатьЭлемент();
Элемент.ОбменДанными.Загрузка = Истина;
Элемент.УстановитьСсылкуНового(СтрТаб.Ссылка);
ЗаполнитьЗначенияСвойств(Элемент, СтрТаб);
Элемент.Записать();

На первый взгляд, код написан абсолютно верно. Мы используем режим загрузки данных ОбменДанными.Загрузка = Истина для отключения лишних проверок, жестко сопоставляем GUID с помощью метода УстановитьСсылкуНового(), заполняем реквизиты из строки таблицы значений и выполняем транзакцию записи. Однако сразу после выполнения метода Записать() ссылка в исходной строке таблицы значений СтрТаб.Ссылка визуально становится пустой. При этом сам объект физически создается в базе данных, его можно найти через стандартные функции или интерактивно выбрать в документах, но в коде и отладчике ссылка выглядит незаполненной.

Более того, наблюдается интересная аномалия: при повторной попытке загрузки (если объект уже создан в базе данных) ссылка в таблице значений изначально отображается пустой еще до попытки записи. Если же физически удалить элемент из базы данных приемника и повторить обмен, ссылка в таблице значений снова становится видимой (в виде стандартного сообщения о битой ссылке: «Объект не найден...») вплоть до момента вызова метода Записать().

Проанализируем причины такого поведения и выясним, как платформа 1С работает со ссылочными типами данных «под капотом».

Механика платформы: Иллюзия «пустой» ссылки

Главный секрет этой проблемы кроется в разнице между физическим значением ссылки (его уникальным идентификатором GUID) и его визуальным представлением на экране, в формах, таблицах значений или табло отладчика.

Когда мы получаем десериализованную ссылку до момента записи объекта в базу данных приемника, эта ссылка является «битой» (несуществующей). Платформа 1С не может найти в базе данных запись с таким GUID, поэтому стандартный механизм отображения выводит пользователю строковое представление вида «Объект не найден (Уникальный_Идентификатор)». В этот момент мы отчетливо видим, что переменная содержит данные.

Как только мы выполняем метод Записать(), объект физически появляется в таблицах СУБД. Теперь это валидная, существующая ссылка. При попытке отобразить ее в таблице значений или в отладчике платформа больше не выводит строку «Объект не найден...». Вместо этого она обращается к механизму получения представления этого объекта базы данных.

Если в конфигурации переопределен алгоритм генерации представления для данного справочника (в модуле менеджера), платформа передает управление туда. И если этот алгоритм написан некорректно или рассчитывает на наличие реквизитов, которые не были заполнены при обмене, процедура может вернуть пустую строку "". В результате в интерфейсе и отладчике ссылка отображается как абсолютно пустая строка, хотя физически в ней по-прежнему записан правильный GUID.

Где скрывается ошибка: Модуль менеджера справочника

В платформе 1С начиная с версии 8.3 представление ссылочных объектов настраивается в модуле менеджера с помощью двух стандартных событий: ОбработкаПолученияПолейПредставления и ОбработкаПолученияПредставления.

Рассмотрим типичный пример кода в модуле менеджера, который приводит к подобной ошибке:


Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    Поля.Добавить("СпециальныйКодПоиска");
    Поля.Добавить("СокращенноеНаименование");
    СтандартнаяОбработка = Ложь;
КонецПроцедуры

Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    // Опасный код без проверок на заполненность реквизитов
    Представление = СокрЛП(Данные.СпециальныйКодПоиска) + " — " + СокрЛП(Данные.СокращенноеНаименование);
    СтандартнаяОбработка = Ложь;
КонецПроцедуры

Если при переносе данных реквизиты СпециальныйКодПоиска или СокращенноеНаименование не были заполнены (например, они не переносились из источника или заполняются позже другими механизмами), структура Данные будет содержать пустые значения или вообще не будет содержать этих полей.

В результате сложения пустых строк переменная Представление получает значение "" (пустая строка). Платформа послушно выводит эту пустую строку везде, где требуется показать ссылку. Разработчик видит пустое поле и делает ложный вывод о том, что ссылка стерлась или очистилась при записи.

Как проверить, действительно ли ссылка пустая?

Чтобы быстро локализовать проблему и убедиться, что дело именно в визуальном представлении, а не в физическом занулении ссылки, выполните следующие шаги в процессе отладки:

  1. Запустите отладку кода и установите точку останова непосредственно после строки Элемент.Записать();.
  2. Откройте табло отладчика (сочетание клавиш Ctrl + Alt + W).
  3. Вместо вычисления выражения СтрТаб.Ссылка, которое визуально покажет пустоту, вычислите уникальный идентификатор этой ссылки: СтрТаб.Ссылка.УникальныйИдентификатор().

Если в табло вывелся строковый GUID вида "de305d54-75b4-431b-adb2-eb6b9ff05fbc", значит, физически ссылка полностью сохранена и корректно записана в базу данных. Проблема со стопроцентной вероятностью заключается в обработчиках получения представления в модуле менеджера.

Решение проблемы: Корректное написание обработчиков представления

Чтобы избежать подобных ошибок при интеграции систем, необходимо соблюдать правила безопасной разработки при переопределении представлений. Напишем надежный код для модуля менеджера справочника, который защитит систему от пустых представлений даже в случае частичного заполнения данных при импорте.

Рассмотрим правильный вариант реализации обработчиков:


Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    // Указываем дополнительные поля, необходимые для формирования представления
    Поля.Добавить("СпециальныйКодПоиска");
    Поля.Добавить("СокращенноеНаименование");
    // Обязательно оставляем стандартную обработку в Истина, 
    // чтобы платформа могла откатиться к стандартному наименованию при отсутствии данных
    СтандартнаяОбработка = Истина;
КонецПроцедуры

Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    
    // 1. Проверяем, передана ли вообще структура с данными
    Если Данные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // 2. Безопасно извлекаем значения реквизитов с проверкой их наличия в структуре
    КодПоиска = "";
    Если Данные.Свойство("СпециальныйКодПоиска") Тогда
        КодПоиска = СокрЛП(Данные.СпециальныйКодПоиска);
    КонецЕсли;
    
    Наименование = "";
    Если Данные.Свойство("СокращенноеНаименование") Тогда
        Наименование = СокрЛП(Данные.СокращенноеНаименование);
    КонецЕсли;
    
    // 3. Формируем представление только если ключевые поля заполнены
    Если ЗначениеЗаполнено(КодПоиска) Или ЗначениеЗаполнено(Наименование) Тогда
        
        Если ЗначениеЗаполнено(КодПоиска) И ЗначениеЗаполнено(Наименование) Тогда
            Представление = КодПоиска + " — " + Наименование;
        ИначеЕсли ЗначениеЗаполнено(КодПоиска) Тогда
            Представление = КодПоиска;
        Иначе
            Представление = Наименование;
        КонецЕсли;
        
        // Отключаем стандартную обработку, так как кастомное представление сформировано успешно
        СтандартнаяОбработка = Ложь;
        
    Иначе
        // Если все наши кастомные поля пусты (например, при загрузке незаполненного объекта),
        // возвращаем стандартное системное представление (Код или Наименование по умолчанию)
        СтандартнаяОбработка = Истина;
    КонецЕсли;
    
КонецПроцедуры

Важные правила при работе с обработчиками представления

Поскольку процедуры модуля менеджера для получения представлений вызываются платформой непрерывно (при выводе каждого элемента в списки, динамические списки, отчеты, формы выбора и даже при формировании записей журналов регистрации), к ним предъявляются повышенные требования надежности и производительности:

Таким образом, мы детально разобрали неочевидную техническую проблему работы платформы 1С с представлениями объектов. Использование безопасного извлечения свойств в модуле менеджера и умение проверять реальное значение ссылки через уникальный идентификатор в отладчике уберегут вас от подобных ошибок интеграции в будущем.

← На главную