В конфигурациях, работающих на обычных формах (например, 1С:Бухгалтерия предприятия 2.0 или Управление торговлей 10.3), механизм дополнительных реквизитов реализован через регистр сведений ЗначенияСвойствОбъектов. Часто возникает задача получить значение такого реквизита (например, некий внешний идентификатор «id») одновременно с основными данными объекта (например, фамилией физического лица) в одном запросе. Разберем, как это сделать правильно, эффективно и с учетом особенностей платформы 1С.
Для начала проанализируем структуру регистра. Он имеет два ключевых измерения: Объект (ссылка на элемент справочника или документа) и Свойство (ссылка на план видов характеристик СвойстваОбъектов). Значение самого реквизита хранится в ресурсе Значение. Тип данных в этом ресурсе обычно составной, что накладывает определенные требования к написанию запросов.
Рассмотрим типичную ошибку начинающих разработчиков: попытку соединить таблицу свойств с основной таблицей по полю Значение. Это логически неверно, так как связывать записи нужно по ссылке на сам объект. Давайте разберем правильный алгоритм построения запроса.
Использование временных таблиц — это «золотой стандарт» разработки в 1С. Такой подход делает код читаемым и облегчает отладку. Проанализируем пример запроса, который выбирает значение дополнительного реквизита для физического лица и присоединяет к нему его актуальную фамилию.
Сначала мы выбираем нужные нам дополнительные реквизиты во временную таблицу, фильтруя их по конкретному свойству. Затем соединяем эту таблицу с регистром сведений, хранящим ФИО.
ВЫБРАТЬ
ЗСО.Объект КАК ФизЛицо,
ЗСО.Значение КАК ДопРеквизит_ID
ПОМЕСТИТЬ ВТ_ДопРеквизиты
ИЗ
РегистрСведений.ЗначенияСвойствОбъектов КАК ЗСО
ГДЕ
ЗСО.Свойство = &Свойство_ID;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ДопРеквизиты.ФизЛицо КАК ФизЛицо,
ДопРеквизиты.ДопРеквизит_ID КАК Идентификатор,
ЕСТЬNULL(ФИОФизЛицСрезПоследних.Фамилия, "") КАК Фамилия
ИЗ
ВТ_ДопРеквизиты КАК ДопРеквизиты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизЛиц.СрезПоследних(&Период, ) КАК ФИОФизЛицСрезПоследних
ПО ДопРеквизиты.ФизЛицо = ФИОФизЛицСрезПоследних.ФизЛицо
Важный нюанс: Обратите внимание на использование виртуальной таблицы СрезПоследних для регистра ФИОФизЛиц. Поскольку фамилия может меняться со временем, обычное соединение с физической таблицей регистра может привести к дублированию строк, если у человека в истории было несколько фамилий. Использование СрезПоследних гарантирует получение одной актуальной записи на указанную дату.
Если вам не нужно строить сложный отчет, а требуется получить значение реквизита для одного конкретного объекта в коде, можно воспользоваться функцией-оберткой. Рассмотрим пример реализации такой функции, которая ищет свойство по наименованию и возвращает его значение.
Функция ОпределитьЗначениеСвойства(ИмяСвойства, ВыбОбъект) Экспорт
ЗначСвойства = Неопределено;
// Поиск свойства в Плане Видов Характеристик
СсылкаНаСвойство = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию(ИмяСвойства);
Если СсылкаНаСвойство.Пустая() Тогда
Возврат Неопределено;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗСО.Значение
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗСО
|ГДЕ
| ЗСО.Объект = &ВыбОбъект
| И ЗСО.Свойство = &ВыбСвойство";
Запрос.УстановитьПараметр("ВыбОбъект", ВыбОбъект);
Запрос.УстановитьПараметр("ВыбСвойство", СсылкаНаСвойство);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ЗначСвойства = Выборка.Значение;
КонецЕсли;
Возврат ЗначСвойства;
КонецФункции
Совет эксперта: Использование метода НайтиПоНаименованию считается «небезопасным», так как пользователь может случайно изменить название свойства в режиме «Предприятие». В идеале ссылку на свойство лучше передавать через параметры настроек или использовать предопределенные элементы, если конфигурация позволяет их создавать для ПВХ.
Посмотрим на ситуацию, когда значение доп. реквизита нужно использовать в арифметических операциях (например, сложить «id» с чем-то еще). Поскольку ресурс Значение имеет составной тип, система может вернуть NULL или данные неожидаемого типа.
Проанализируем способы защиты от таких ошибок:
ЕСТЬNULL(Поле, 0) или ЕСТЬNULL(Поле, ""). Это предотвратит ошибки при попытке сложения чисел или конкатенации строк.ВЫРАЗИТЬ(Значение КАК ЧИСЛО(15,2)). Это явно укажет системе, как интерпретировать данные из составного типа.ЗначенияСвойствОбъектов поиск по комбинации Объект + Свойство работает максимально быстро благодаря штатным индексам платформы.Если вы перешли на редакцию 3.0, структура хранения изменилась. Теперь вместо ЗначенияСвойствОбъектов используются регистры ДополнительныеСведения или табличные части ДополнительныеРеквизиты внутри самих объектов. Поиск свойств в ПВХ ДополнительныеРеквизитыИСведения теперь чаще выполняется по внутреннему имени (реквизит Имя), а не по заголовку.
Пример получения свойства в БП 3.0 через уникальное имя:
ТекСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "ТипЭДО_3f5e1013ee924a85ad63b6f084bebd37");
Этот метод гораздо надежнее, так как внутреннее имя формируется программно и не меняется при редактировании заголовка пользователем.
Подведем итог: для эффективного извлечения доп. реквизитов в БП 2.0 используйте запросы с левым соединением по полю Объект, не забывайте про СрезПоследних для периодических регистров и всегда приводите типы данных с помощью ВЫРАЗИТЬ.