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