Как программно обратиться к значению дополнительного реквизита и реализовать контроль его уникальности?

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

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

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

Почему не работает стандартный контроль уникальности?

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

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

Как обратиться к дополнительному реквизиту на форме (клиент)

Рассмотрим ситуацию, когда нам нужно получить значение доп. реквизита непосредственно в модуле формы. Поскольку элементы для них создаются динамически, мы не можем обратиться к ним просто как Объект.ИмяРеквизита.

Один из способов, предложенных участниками сообщества, — это использование внутреннего имени, которое генерирует БСП. Имя формируется по шаблону: "ДополнительныйРеквизитЗначение_" + ГУИД_Свойства + "_" + ГУИД_НабораСвойств.

Посмотрим на пример обращения к такому элементу через ЭтаФорма:


// Пример получения значения через динамическое имя реквизита формы
ИмяРеквизита = "ДополнительныйРеквизитЗначение_D23B5F4Fx061Ax4C28x9CC7xF7EDE71C8AB7_C88BD832xE229x11F0x9D37x00155D316B00";
Значение = ЭтаФорма[ИмяРеквизита];

Важно: Этот метод считается «грязным», так как имена могут меняться при обновлении БСП или изменении структуры наборов свойств. Разберем более цивилизованный метод, используя программный перебор коллекции свойств формы:


// Безопасный поиск значения на форме
Для Каждого СтрокаСвойство Из ЭтаФорма.Свойства_ОписаниеДополнительныхРеквизитов Цикл
    Если СтрокаСвойство.Свойство = ИскомоеСвойствоСсылка Тогда
        ТекущееЗначение = ЭтаФорма[СтрокаСвойство.ИмяРеквизитаЗначение];
        Прервать;
    КонецЕсли;
КонецЦикла;

Как получить значение дополнительного реквизита на сервере

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

Разберем пример получения значения:


// Получение значения дополнительного реквизита на сервере
Значение = УправлениеСвойствами.ЗначениеСвойства(ОбъектСсылкаИлиОбъект, ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("МойРеквизит"));

Этот метод универсален: он работает как с уже записанными ссылками, так и с объектами, находящимися в памяти.

Реализация контроля уникальности через расширение

Теперь перейдем к основной задаче — контролю уникальности. Самым правильным местом для такой проверки является обработчик ПередЗаписью в модуле объекта (через расширение) или ОбработкаПроверкиЗаполнения.

Выясним причину выбора именно этого места: ПередЗаписью гарантирует, что проверка сработает всегда, независимо от того, записывается объект из формы или программно из другой обработки.

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


&После("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // 1. Находим наше свойство (лучше использовать предопределенный элемент или поиск по ГУИД)
    СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СерийныйНомер");
    
    // 2. Получаем текущее значение из табличной части объекта
    СтрокаДопРеквизита = ДополнительныеРеквизиты.Найти(СвойствоСсылка, "Свойство");
    
    Если СтрокаДопРеквизита = Неопределено Или ПустаяСтрока(СтрокаДопРеквизита.Значение) Тогда
        Возврат;
    КонецЕсли;
    
    // 3. Выполняем запрос для поиска дублей
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	СправочникОбъект.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.Контрагенты.ДополнительныеРеквизиты КАК ТЧ
        |ГДЕ
        |	ТЧ.Свойство = &Свойство
        |	И ТЧ.Значение = &Значение
        |	И ТЧ.Ссылка <> &ТекущаяСсылка";
        
    Запрос.УстановитьПараметр("Свойство", СвойствоСсылка);
    Запрос.УстановитьПараметр("Значение", СтрокаДопРеквизита.Значение);
    Запрос.УстановитьПараметр("ТекущаяСсылка", Ссылка);
    
    Результат = Запрос.Выполнить();
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
            СтрШаблон("Значение '%1' уже используется в объекте %2!", СтрокаДопРеквизита.Значение, Выборка.Ссылка),
            ,
            "ДополнительныеРеквизиты",
            ,
            Отказ);
    КонецЕсли;

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

Оптимизация производительности для больших баз

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

  1. Создаем в расширении независимый регистр сведений КонтрольУникальностиДопРеквизитов.
  2. В качестве измерения указываем тип значения нашего доп. реквизита (например, Строка).
  3. В качестве ресурса указываем ЛюбаяСсылка (ссылка на объект справочника).
  4. При записи объекта обновляем запись в этом регистре.

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

Альтернатива: Дополнительные сведения

Если специфика бизнес-процесса позволяет, проанализируем возможность использования Дополнительных сведений вместо реквизитов. Сведения хранятся в отдельном регистре ДополнительныеСведения. Поскольку это полноценный регистр сведений, проверка уникальности по нему осуществляется гораздо проще и быстрее штатными средствами языка запросов.

Резюмируем: Для контроля уникальности доп. реквизита в 1С наиболее эффективным решением является использование расширения с перехватом события ПередЗаписью и выполнением запроса по табличной части или вспомогательному регистру. Выбор конкретного метода зависит от объема данных и требований к производительности системы.

← На главную