Почему при присвоении ссылки из расширения реквизиту Любая ссылка во внешней обработке значение становится Неопределено

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает ситуация, когда внешняя обработка должна взаимодействовать с данными, добавленными через расширения конфигурации. Типичный сценарий: во внешней обработке создан реквизит (или колонка табличной части) с типом Любая ссылка, и мы пытаемся записать туда ссылку на справочник, существующий только в расширении. Однако при выполнении кода НовСтр.Ссылка = Выборка.Ссылка; мы с удивлением обнаруживаем, что значение превращается в Неопределено. Разберем подробно, почему это происходит и как правильно решить данную задачу.

Проанализируем причину возникновения ошибки

Первым делом нам необходимо понять, как работает тип данных Любая ссылка. Вопреки названию, этот тип не является абсолютно универсальным «контейнером» для любых ссылок в системе. Когда вы создаете внешнюю обработку (файл .epf) в конфигураторе, платформа фиксирует список типов, которые входят в состав Любая ссылка, исходя из метаданных основной конфигурации.

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

Решение №1: Программное изменение описания типов

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

Рассмотрим, как это реализовать программно. Нам нужно создать новый массив типов, включив в него как стандартные типы, так и типы из расширения, а затем назначить это описание реквизиту. Выясним, как получить тип из расширения, если мы не можем выбрать его визуально:


// Пример добавления типа из расширения в описание типов колонки
МассивТипов = Новый Массив;
// Добавляем стандартный тип (например, все ссылки)
МассивТипов.Добавить(Тип("СправочникСсылка.Номенклатура")); 

// Добавляем тип из расширения по его строковому имени
// Важно: укажите префикс, если он есть в расширении
ТипИзРасширения = Тип("СправочникСсылка.ПРФ_МойСправочникИзРасширения");
Если ТипИзРасширения <> Неопределено Тогда
    МассивТипов.Добавить(ТипИзРасширения);
КонецЕсли;

НовоеОписание = Новый ОписаниеТипов(МассивТипов);

// Если работаем с колонкой таблицы значений на форме:
Элементы.ТаблицаДанныхКолонкаСсылка.ОграничениеТипа = НовоеОписание;

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

Решение №2: Использование Таблицы Значений на форме

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


// Программное создание колонки ТЗ с поддержкой типов расширений
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Валюты")); // пример
// Если нужно разрешить вообще все ссылки, используем конструктор ОписаниеТипов
// Однако для расширений лучше указывать типы явно или собирать их перебором

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("СсылкаНаОбъект", Новый ОписаниеТипов("СправочникСсылка.ПРФ_МойСправочник"));

// Теперь присвоение будет работать корректно
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.СсылкаНаОбъект = Справочники.ПРФ_МойСправочник.НайтиПоКоду("001");

Решение №3: Обходной путь через строковое представление GUID

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

  1. Создаем в табличной части обработки реквизит с типом Строка (длиной 36 символов для GUID) и реквизит ИмяТипа (строка).
  2. При заполнении сохраняем Строка(Выборка.Ссылка.УникальныйИдентификатор()) и имя метаданных справочника.
  3. В момент, когда ссылка нужна для работы (например, для открытия формы или печати), восстанавливаем её.

Проанализируем код восстановления ссылки:


// Восстановление ссылки из строки GUID
ИмяТипа = "Справочник.ПРФ_МойСправочник";
ГУИД = Новый УникальныйИдентификатор(СтрокаИзРеквизита);
Ссылка = Справочники[ИмяТипа].ПолучитьСсылку(ГУИД);

Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
    Сообщить("Объект не найден в базе!");
КонецЕсли;

Внимание: Этот способ является трудозатратным и менее производительным, так как требует дополнительных операций поиска. Используйте его только в крайнем случае, если динамическое управление ОписаниеТипов недоступно.

Посмотрим на влияние режима совместимости и контекста

Выясним еще одну важную деталь: часто ошибка Неопределено возникает из-за того, что обработка запущена «вне контекста». Если в свойствах расширения не стоит галочка «Использовать в основных типах», или если режим совместимости конфигурации ниже 8.3.10, работа с типами расширений во внешних файлах может быть нестабильной.

Всегда проверяйте в отладчике значение Выборка.Ссылка непосредственно перед присвоением. Если там уже Неопределено, значит, запрос выполняется в контексте, где расширение неактивно или типы не видны. Если же в Выборка.Ссылка есть валидная ссылка, а после присвоения в НовСтр.Ссылка значение пропадает — значит, мы столкнулись именно с ограничением ОписаниеТипов, описанным выше.

Резюме для реализации решения

Подведем итоги нашей совместной работы. Чтобы ваша внешняя обработка успешно принимала ссылки из справочников расширения, следуйте этим правилам:

  1. Избегайте жесткой типизации в метаданных .epf файла, если заранее знаете, что данные могут прийти из расширений.
  2. Для отображения данных на форме используйте Таблицу Значений (реквизит формы), а колонки создавайте программно, задавая им ОписаниеТипов с помощью конструктора от строки: Новый ОписаниеТипов("СправочникСсылка.ИмяИзРасширения").
  3. Если используете тип Любая ссылка, перед заполнением данных программно обновите ОграничениеТипа этого реквизита, добавив туда нужные типы из расширения через Массив.
  4. Помните про префиксы расширений. Если справочник в расширении называется Расш1_Склады, то и в коде к нему нужно обращаться именно по этому полному имени.

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

← На главную