При разработке расширений для платформы 1С:Предприятие 8.3 программисты часто сталкиваются с жестким ограничением: невозможностью выбрать тип данных ЛюбаяСсылка для новых реквизитов или ресурсов. Это ограничение обусловлено архитектурой платформы — состав системного типа ЛюбаяСсылка формируется на уровне основной конфигурации, и расширение не может динамически изменять этот глобальный тип, чтобы не нарушать ссылочную целостность базы данных.
В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько эффективных стратегий обхода данного ограничения, от использования составных типов до различных методов сериализации данных.
Разберем ситуацию глубже. Тип ЛюбаяСсылка в 1С — это не просто абстрактный указатель, а объединение всех ссылочных типов конфигурации (справочников, документов, планов видов характеристик и т.д.). Когда мы создаем расширение, платформа должна гарантировать, что данные расширения будут корректно сопоставляться с основной базой. Поскольку расширение "накладывается" на основную конфигурацию, динамическое расширение типа ЛюбаяСсылка объектами самого расширения или попытка его использования в новых структурах данных заблокирована на уровне ядра 1С для обеспечения стабильности SQL-таблиц.
Если нам заранее известен примерный перечень типов объектов, которые могут быть записаны в ресурс регистра, самым правильным и производительным решением будет использование составного типа данных. Рассмотрим, как это реализовать.
Проанализируем шаги:
Важный нюанс: Если в основной конфигурации появятся новые объекты метаданных, которые также должны попадать в этот регистр, нам придется зайти в расширение и вручную добавить их в составной тип. Это минус данного метода. Однако огромный плюс в том, что сохраняется ссылочная целостность: 1С будет отслеживать использование объектов, и они не будут удалены без соответствующей проверки.
Если же нам действительно необходимо хранить абсолютно любую ссылку (в том числе на объекты, которые появятся в будущем), воспользуемся методом сериализации. Вместо ссылки мы будем хранить текстовое представление объекта.
Рассмотрим использование метода ЗначениеВСтрокуВнутр. Этот метод позволяет преобразовать любой объект 1С (включая ссылку) в уникальную системную строку.
Для записи данных используем следующий подход:
// Пример записи ссылки в ресурс типа Строка
НоваяЗапись = РегистрыСведений.МойРегистрРасширения.СоздатьМенеджерЗаписи();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.ОбъектСтрокой = ЗначениеВСтрокуВнутр(СсылкаНаОбъект);
НоваяЗапись.Записать();
Для обратного получения ссылки из регистра проанализируем следующий код:
// Получение ссылки из строки
ТекСтрока = ЗаписьРегистра.ОбъектСтрокой;
Попытка
СсылкаНаОбъект = ЗначениеИзСтрокиВнутр(ТекСтрока);
Исключение
СсылкаНаОбъект = Неопределено;
КонецПопытки;
Этот способ позволяет обойти любые ограничения типов, но делает невозможным построение запросов с отбором по самой ссылке внутри базы данных, так как в SQL будет лежать просто текст.
Это более профессиональный и "чистый" метод. Вместо одной непонятной строки мы создаем в регистре два ресурса:
ИмяТипа (Тип: Строка) — здесь будем хранить полное имя метаданных, например, "Справочник.Номенклатура".Идентификатор (Тип: Строка или УникальныйИдентификатор) — здесь будем хранить GUID ссылки.Выясним, как программно восстановить ссылку, имея эти данные. Для этого воспользуемся возможностями XML-сериализации, которая позволяет гибко работать с типами:
// Функция для восстановления ссылки из метаданных и GUID
Функция ПолучитьСсылкуИзПараметров(ИмяМетаданных, СтрокаGUID) Экспорт
ТипОбъекта = Тип(ИмяМетаданных);
Если ТипОбъекта = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
// Используем XMLЗначение для получения ссылки по типу и идентификатору
Попытка
Возврат XMLЗначение(ТипОбъекта, СтрокаGUID);
Исключение
Возврат Неопределено;
КонецПопытки;
КонецФункции
Такой подход позволяет нам не только хранить произвольные ссылки, но и при необходимости строить отчеты, группируя данные хотя бы по типам объектов (через поле ИмяТипа).
Платформа 1С позволяет создавать в расширениях ресурсы с типом ХранилищеЗначения. В такой ресурс можно "упаковать" любой объект, включая ссылку или даже структуру с данными.
Посмотрим на пример записи:
Запись = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
// ... заполнение ключей записи ...
Запись.ДанныеОбъекта = Новый ХранилищеЗначения(СсылкаНаЛюбойОбъект);
Запись.Записать();
Важно помнить, что содержимое ХранилищеЗначения нельзя прочитать в запросе. Этот способ подходит только для тех случаев, когда данные нужны исключительно при чтении записи программным кодом (например, в формах или при обработке данных в фоне).
Рассмотрим риски, которые возникают при использовании обходных путей:
Объект.ПолучитьОбъект() = Неопределено.ГДЕ Ресурс = &Ссылка, если ресурс является строкой или хранилищем. Поиск по строковому GUID будет значительно медленнее, чем по индексированному ссылочному полю.ЗначениеВСтрокуВнутр) занимает значительно больше места в таблицах SQL, чем стандартный тип UUID.Подведем итог и выберем оптимальный путь для вашей задачи:
ЗначениеВСтрокуВнутр прибегайте только в крайнем случае, так как этот формат является внутренним для 1С и его трудно анализировать внешними средствами (например, через консоль запросов или напрямую в SQL).Таким образом, несмотря на отсутствие прямой поддержки ЛюбаяСсылка в расширениях, платформа предоставляет достаточно инструментов для решения этой задачи. Главное — заранее продумать, как вы будете обрабатывать удаление объектов и строить отчеты по этим данным.