Как добавить новый ресурс в заимствованный регистр сведений в расширении 1С?

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

При активной работе с расширениями в платформе «1С:Предприятие 8.3» разработчики часто сталкиваются с неприятным ограничением: при попытке заимствовать регистр сведений из основной конфигурации ветка «Ресурсы» (а также «Измерения» и «Реквизиты») блокируется для добавления новых элементов. Кнопка «Добавить» просто отсутствует, и платформа не позволяет напрямую расширить структуру существующей таблицы.

В этой статье мы подробно разберем, почему платформа ведет себя именно так, проанализируем технические аспекты этого ограничения СУБД, а также рассмотрим три практических способа решения этой задачи, которые применяются в реальной практике разработки.

Почему платформа накладывает такое ограничение?

Давайте выясним причину, по которой разработчики платформы «1С» заблокировали возможность добавления собственных ресурсов в заимствованные регистры сведений. Всё дело в физической структуре хранения данных в СУБД (MS SQL Server, PostgreSQL и др.):

По этой причине разработчики «1С» жестко заблокировали изменение состава измерений и ресурсов заимствованных регистров. Тем не менее, решить задачу хранения дополнительных данных по существующим измерениям необходимо. Рассмотрим рабочие архитектурные паттерны.

Способ 1. Создание параллельного регистра в расширении (Вертикальное расщепление)

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

Разберем по шагам, как реализовать этот паттерн:

  1. Создание регистра в расширении: Создадим новый регистр сведений непосредственно в расширении конфигурации (например, под именем Расш1_ДополнительныеСвойстваНоменклатуры). Обратите внимание: создавать его нужно как абсолютно новый объект расширения, а не заимствовать исходный.
  2. Перенос измерений: Перенесем (заимствуем) типы данных измерений из основного регистра. В нашем новом регистре создаем точно такие же измерения с аналогичными типами данных. Например, если в основном регистре ключевым полем является Номенклатура (с типом СправочникСсылка.Номенклатура) и Характеристика (с типом СправочникСсылка.ХарактеристикиНоменклатуры), мы создаем точно такие же измерения в нашем новом регистре в расширении.
  3. Добавление ресурса: Добавляем в наш новый регистр сведений нужный ресурс (например, Расш1_ДополнительныйПараметр с требуемым типом данных).
  4. Организация записи данных: Чтобы исключить необходимость переписывать документы-регистраторы и обработчики по всей системе, настроим автоматическую запись в наш параллельный регистр при записи в основной. Для этого заимствуем модуль набора записей основного регистра сведений и перехватим событие ПриЗаписи.

Рассмотрим пример программного кода в расширении для синхронизации записи данных. Мы используем аннотацию &После для перехвата события записи основного регистра:


&После("ПриЗаписи")
Процедура Расш1_ПриЗаписи(Отказ, Замещение)
    
    // Если запись инициирована с отказом, ничего не делаем
    Если Отказ Тогда
        Возврат;
    КонецЕсли;
    
    // Блокируем запись нашего параллельного регистра, чтобы избежать коллизий
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Расш1_ДополнительныеСвойстваНоменклатуры");
    // Устанавливаем пространство блокировки на основе структуры измерений текущего набора записей
    // ...
    
    // Создаем набор записей нашего нового регистра
    НаборПараллельный = РегистрыСведений.Расш1_ДополнительныеСвойстваНоменклатуры.СоздатьНаборЗаписей();
    
    // Переносим отборы из текущего (заимствованного) набора записей
    Для Каждого ЭлементОтбора Из ЭтотОбъект.Отбор Цикл
        ЗаполнитьЗначенияСвойств(НаборПараллельный.Отбор[ЭлементОтбора.Имя], ЭлементОтбора);
    КонецЦикла;
    
    // Читаем существующий набор, если необходимо обновить только конкретный ресурс
    НаборПараллельный.Прочитать();
    
    // Очищаем или заполняем новые записи на основании данных исходного набора
    Если ЭтотОбъект.Количество() = 0 Тогда
        // Если исходный набор очищен, очищаем и наш параллельный регистр
        НаборПараллельный.Очистить();
    Иначе
        Для Каждого СтрокаОсновная Из ЭтотОбъект Цикл
            // Ищем строку в параллельном наборе по ключевым измерениям
            ПараметрыОтбора = Новый Структура("Номенклатура, Характеристика", СтрокаОсновная.Номенклатура, СтрокаОсновная.Характеристика);
            НайденныеСтроки = НаборПараллельный.НайтиСтроки(ПараметрыОтбора);
            
            Если НайденныеСтроки.Количество() > 0 Тогда
                НоваяСтрока = НайденныеСтроки[0];
            Иначе
                НоваяСтрока = НаборПараллельный.Добавить();
                ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаОсновная);
            КонецЕсли;
            
            // Заполняем наш новый ресурс (значение можно получать из контекста или параметров формы)
            // НоваяСтрока.Расш1_ДополнительныйПараметр = ...
        КонецЦикла;
    EndIf;
    
    Попытка
        НаборПараллельный.Записать(Истина);
    Исключение
        ЗаписьЖурналаРегистрации("Расширение.РегистрСведений", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        Отказ = Истина;
    КонецПопытки;

КонецПроцедуры

При чтении данных (например, при построении отчетов на СКД или динамических списков) мы просто связываем две таблицы левым соединением по ключевым полям-измерениям:


ВЫБРАТЬ
    ОсновнойРегистр.Номенклатура КАК Номенклатура,
    ОсновнойРегистр.Характеристика КАК Характеристика,
    ОсновнойРегистр.ОсновнойРесурс КАК ОсновнойРесурс,
    ЕСТЬNULL(ПараллельныйРегистр.Расш1_ДополнительныйПараметр, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК ДополнительныйРесурс
ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК ОсновнойРегистр
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Расш1_ДополнительныеСвойстваНоменклатуры КАК ПараллельныйРегистр
        ПО ОсновнойРегистр.Номенклатура = ПараллельныйРегистр.Номенклатура
        И ОсновнойРегистр.Характеристика = ПараллельныйРегистр.Характеристика

Способ 2. Использование механизма дополнительных сведений БСП

Если ваша конфигурация разработана на основе 1С:Библиотеки стандартных подсистем (БСП), то во многих случаях изменять структуру таблиц вообще не требуется. Для этого предназначен механизм «Дополнительные реквизиты и сведения».

Проанализируем этот вариант подробнее:

Способ 3. Внесение изменений в основную конфигурацию (Рекомендуемый подход)

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

Рекомендуемый стандарт разработки (Best Practice) в сообществе 1С выглядит следующим образом:

  1. В основной конфигурации аккуратно включается возможность изменения (устанавливается режим «Редактируется с сохранением поддержки»).
  2. Сам новый ресурс добавляется **непосредственно в структуру оригинального регистра** в основной конфигурации. Это гарантирует максимальное быстродействие СУБД, физическую целостность транзакций и оптимальную работу индексов. При обновлении конфигурации добавленные вручную новые реквизиты или ресурсы не затираются, если правильно настроить правила обновления.
  3. Вся логика заполнения, измененные экранные формы, перехват событий и алгоритмы расчета этого нового ресурса выносятся **в расширение**. Таким образом, программный код основной конфигурации остается на 100% типовым, что позволяет обновлять базу данных быстро и без ошибок.

Выбор конкретного решения всегда остается за архитектором системы. Если вам требуется быстрое решение «здесь и сейчас» без изменения основной конфигурации, используйте **Способ 1** (создание параллельного регистра в расширении). Если же база данных высоконагруженная и предполагается активная работа с регистром в тяжелых отчетах, правильнее использовать **Способ 3** и добавить ресурс в основную конфигурацию, вынеся всю логику его обработки в расширение.

← На главную