Как вытащить дополнительный реквизит из регистра сведений запросом в 1С:Бухгалтерия 2.0

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия
← На главную

В конфигурациях, работающих на обычных формах (например, 1С:Бухгалтерия предприятия 2.0 или Управление торговлей 10.3), механизм дополнительных реквизитов реализован через регистр сведений ЗначенияСвойствОбъектов. Часто возникает задача получить значение такого реквизита (например, некий внешний идентификатор «id») одновременно с основными данными объекта (например, фамилией физического лица) в одном запросе. Разберем, как это сделать правильно, эффективно и с учетом особенностей платформы 1С.

Основы работы с регистром ЗначенияСвойствОбъектов

Для начала проанализируем структуру регистра. Он имеет два ключевых измерения: Объект (ссылка на элемент справочника или документа) и Свойство (ссылка на план видов характеристик СвойстваОбъектов). Значение самого реквизита хранится в ресурсе Значение. Тип данных в этом ресурсе обычно составной, что накладывает определенные требования к написанию запросов.

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

Вариант 1. Запрос с использованием временных таблиц

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

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


ВЫБРАТЬ
    ЗСО.Объект КАК ФизЛицо,
    ЗСО.Значение КАК ДопРеквизит_ID
ПОМЕСТИТЬ ВТ_ДопРеквизиты
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗСО
ГДЕ
    ЗСО.Свойство = &Свойство_ID;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ДопРеквизиты.ФизЛицо КАК ФизЛицо,
    ДопРеквизиты.ДопРеквизит_ID КАК Идентификатор,
    ЕСТЬNULL(ФИОФизЛицСрезПоследних.Фамилия, "") КАК Фамилия
ИЗ
    ВТ_ДопРеквизиты КАК ДопРеквизиты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизЛиц.СрезПоследних(&Период, ) КАК ФИОФизЛицСрезПоследних
        ПО ДопРеквизиты.ФизЛицо = ФИОФизЛицСрезПоследних.ФизЛицо

Важный нюанс: Обратите внимание на использование виртуальной таблицы СрезПоследних для регистра ФИОФизЛиц. Поскольку фамилия может меняться со временем, обычное соединение с физической таблицей регистра может привести к дублированию строк, если у человека в истории было несколько фамилий. Использование СрезПоследних гарантирует получение одной актуальной записи на указанную дату.

Вариант 2. Программное получение значения в коде

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


Функция ОпределитьЗначениеСвойства(ИмяСвойства, ВыбОбъект) Экспорт
    ЗначСвойства = Неопределено;
    
    // Поиск свойства в Плане Видов Характеристик
    СсылкаНаСвойство = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию(ИмяСвойства);
    
    Если СсылкаНаСвойство.Пустая() Тогда
        Возврат Неопределено;
    КонецЕсли;

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЗСО.Значение
        |ИЗ
        |   РегистрСведений.ЗначенияСвойствОбъектов КАК ЗСО
        |ГДЕ
        |   ЗСО.Объект = &ВыбОбъект
        |   И ЗСО.Свойство = &ВыбСвойство";

    Запрос.УстановитьПараметр("ВыбОбъект", ВыбОбъект);
    Запрос.УстановитьПараметр("ВыбСвойство", СсылкаНаСвойство);

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        ЗначСвойства = Выборка.Значение;
    КонецЕсли;

    Возврат ЗначСвойства;
КонецФункции

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

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

Посмотрим на ситуацию, когда значение доп. реквизита нужно использовать в арифметических операциях (например, сложить «id» с чем-то еще). Поскольку ресурс Значение имеет составной тип, система может вернуть NULL или данные неожидаемого типа.

Проанализируем способы защиты от таких ошибок:

  1. Использование функции ЕСТЬNULL: Всегда оборачивайте поля из левых соединений в ЕСТЬNULL(Поле, 0) или ЕСТЬNULL(Поле, ""). Это предотвратит ошибки при попытке сложения чисел или конкатенации строк.
  2. Типизация через ВЫРАЗИТЬ: Чтобы ускорить работу запроса и обеспечить правильную сортировку, используйте конструкцию ВЫРАЗИТЬ(Значение КАК ЧИСЛО(15,2)). Это явно укажет системе, как интерпретировать данные из составного типа.
  3. Индексация: Помните, что в регистре ЗначенияСвойствОбъектов поиск по комбинации Объект + Свойство работает максимально быстро благодаря штатным индексам платформы.

Особенности для 1С:Бухгалтерия 3.0 (Такси)

Если вы перешли на редакцию 3.0, структура хранения изменилась. Теперь вместо ЗначенияСвойствОбъектов используются регистры ДополнительныеСведения или табличные части ДополнительныеРеквизиты внутри самих объектов. Поиск свойств в ПВХ ДополнительныеРеквизитыИСведения теперь чаще выполняется по внутреннему имени (реквизит Имя), а не по заголовку.

Пример получения свойства в БП 3.0 через уникальное имя:


ТекСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "ТипЭДО_3f5e1013ee924a85ad63b6f084bebd37");

Этот метод гораздо надежнее, так как внутреннее имя формируется программно и не меняется при редактировании заголовка пользователем.

Подведем итог: для эффективного извлечения доп. реквизитов в БП 2.0 используйте запросы с левым соединением по полю Объект, не забывайте про СрезПоследних для периодических регистров и всегда приводите типы данных с помощью ВЫРАЗИТЬ.

← На главную