Как обратиться к дополнительным свойствам и реквизитам справочников в 1С из внешней обработки

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

В процессе разработки внешних печатных форм, отчетов или обработок программисты 1С часто сталкиваются с необходимостью вывода данных, которые пользователи добавили самостоятельно в режиме «1С:Предприятие». Это могут быть различные свойства объектов (например, «Юридический адрес», «Внутренний код региона», «Особые условия доставки» для справочников Организации, Контрагенты или Номенклатура). Для ускорения разработки отчетов и форм можно использовать готовый шаблон внешних печатных форм для БСП.

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

Понимаем разницу: Архитектурные различия в 1С

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

  1. Современные конфигурации на базе БСП (Библиотеки стандартных подсистем) — например, ERP 2, УТ 11, КА 2, Бухгалтерия предприятия 3.0. Здесь свойства разделены на два типа:
    • Дополнительные реквизиты: хранятся внутри самого объекта в его табличной части ДополнительныеРеквизиты.
    • Дополнительные сведения: хранятся обособленно от объекта во внешнем регистре сведений ДополнительныеСведения.
  2. Устаревшие конфигурации (без БСП) — например, УПП 1.3, УТ 10.3, КА 1.1. В таких системах все свойства хранятся в едином классическом регистре сведений ЗначенияСвойствОбъектов.

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

---

Сценарий 1. Работа в современных конфигурациях на базе БСП

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

Рассмотрим использование общего модуля УправлениеСвойствами. Этот метод автоматически определяет, где именно хранится нужное свойство (в реквизитах или сведениях), и возвращает готовое значение.

Пример получения одного конкретного свойства:


// СвойствоЮрАдрес — это ссылка на элемент Плана видов характеристик "ДополнительныеРеквизитыИСведения"
СвойствоЮрАдрес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "Организация_ЮридическийАдрес");

Если ЗначениеЗаполнено(СвойствоЮрАдрес) Тогда
    ЗначениеАдреса = УправлениеСвойствами.ЗначениеСвойства(ДокументРеализации.Организация, СвойствоЮрАдрес);
    ОбластьШапки.Параметры.ЮрАдрес = ЗначениеАдреса;
КонецЕсли;

Пример пакетного получения всех свойств объекта:

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


ТаблицаСвойств = УправлениеСвойствами.ЗначенияСвойств(ДокументРеализации.Организация);

Для Каждого СтрокаСвойства Из ТаблицаСвойств Цикл
    Если СтрокаСвойства.Свойство = СвойствоЮрАдрес Тогда
        ОбластьШапки.Параметры.ЮрАдрес = СтрокаСвойства.Значение;
    ИначеЕсли СтрокаСвойства.Свойство = СвойствоПолноеНаименование Тогда
        ОбластьШапки.Параметры.НименованиеОрганиазации = СтрокаСвойства.Значение;
    КонецЕсли;
КонецЦикла;

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

---

Сценарий 2. Прямой обход табличной части (Дополнительные реквизиты)

Если по какой-то причине API БСП недоступно, но мы точно знаем, что нужные данные лежат в дополнительных реквизитах справочника Организации, мы можем перебрать табличную часть объекта.

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


Для Каждого СтрокаРеквизита Из ДокументРеализации.Организация.ДополнительныеРеквизиты Цикл
    // Сравниваем представление или ссылку на свойство
    ИмяСвойства = СокрЛП(СтрокаРеквизита.Свойство.Наименование);
    
    Если ИмяСвойства = "ЮрАдрес (строка)" Тогда
        ОбластьШапки.Параметры.ЮрАдрес = СтрокаРеквизита.Значение;
    ИначеЕсли ИмяСвойства = "НаименованиеОрганизации (строка)" Тогда
        ОбластьШапки.Параметры.НименованиеОрганиазации = СтрокаРеквизита.Значение;
    КонецЕсли;
КонецЦикла;

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

---

Сценарий 3. Работа в старых конфигурациях через регистр «Значения свойств объектов»

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

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


// ОШИБОЧНЫЙ КОД:
Запрос.Текст = "... ГДЕ ЗначенияСвойствОбъектов.Объект = &Объект";
Запрос.УстановитьПараметр("Объект", СписокОтбор); // Вызовет ошибку несовместимости типов!

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


СписокОтбор = Новый СписокЗначений;
СписокОтбор.Добавить(ДокументРеализации.Организация);
СписокОтбор.Добавить(ДокументРеализации.Контрагент);

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

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

---

Сценарий 4. Оптимальный запрос с левыми соединениями (Горизонтальная выборка)

Выборка свойств вертикальным списком (когда для одного объекта возвращается несколько строк) неудобна для заполнения параметров макета. Нам приходится писать дополнительный код для поиска нужных строк в таблице результатов.

Проанализируем наилучший способ получения свойств — горизонтальное развертывание с помощью левых соединений в запросе. Этот метод работает быстро, не перегружает сервер и сразу возвращает одну строку со всеми необходимыми колонками-свойствами.

Рассмотрим пример запроса для конфигураций, использующих регистр ЗначенияСвойствОбъектов:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Реализация.Ссылка КАК Ссылка,
    |	ЕСТЬNULL(ДопСвойствоНаименование.Значение, """") КАК НаименованиеОрганизации,
    |	ЕСТЬNULL(ДопСвойствоЮрАдрес.Значение, """") КАК ЮрАдрес
    |ИЗ
    |	Документ.РеализацияТоваровУслуг КАК Реализация
    |	
    |	// Соединение для получения наименования
    |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ДопСвойствоНаименование
    |		ПО ДопСвойствоНаименование.Объект = Реализация.Организация
    |		И ДопСвойствоНаименование.Свойство = &СвойствоНаименование
    |	
    |	// Соединение для получения юридического адреса
    |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ДопСвойствоЮрАдрес
    |		ПО ДопСвойствоЮрАдрес.Объект = Реализация.Организация
    |		И ДопСвойствоЮрАдрес.Свойство = &СвойствоЮрАдрес
    |ГДЕ
    |	Реализация.Ссылка = &Ссылка";

// Определяем ссылки на элементы ПВХ заранее
СвойствоНаименованиеСсылка = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Наименование организации");
СвойствоЮрАдресСсылка = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("ЮрАдрес");

Запрос.УстановитьПараметр("Ссылка", ДокументРеализации);
Запрос.УстановитьПараметр("СвойствоНаименование", СвойствоНаименованиеСсылка);
Запрос.УстановитьПараметр("СвойствоЮрАдрес", СвойствоЮрАдресСсылка);

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    ОбластьШапки.Параметры.НименованиеОрганиазации = Выборка.НаименованиеОрганизации;
    ОбластьШапки.Параметры.ЮрАдрес = Выборка.ЮрАдрес;
КонецЕсли;

Аналогичным образом левое соединение можно применить к табличной части ДополнительныеРеквизиты справочника в современных конфигурациях:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Организации.Ссылка КАК Ссылка,
    |	ЕСТЬNULL(ДопРеквизитНаименование.Значение, """") КАК НаименованиеОрганизации,
    |	ЕСТЬNULL(ДопРеквизитЮрАдрес.Значение, """") КАК ЮрАдрес
    |ИЗ
    |	Справочник.Организации КАК Организации
    |	
    |	ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.ДополнительныеРеквизиты КАК ДопРеквизитНаименование
    |		ПО ДопРеквизитНаименование.Ссылка = Организации.Ссылка
    |		И ДопРеквизитНаименование.Свойство = &СвойствоНаименование
    |	
    |	ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.ДополнительныеРеквизиты КАК ДопРеквизитЮрАдрес
    |		ПО ДопРеквизитЮрАдрес.Ссылка = Организации.Ссылка
    |		И ДопРеквизитЮрАдрес.Свойство = &СвойствоЮрАдрес
    |ГДЕ
    |	Организации.Ссылка = &Организация";

Запрос.УстановитьПараметр("Организация", ДокументРеализации.Организация);
Запрос.УстановитьПараметр("СвойствоНаименование", СвойствоНаименованиеСсылка);
Запрос.УстановитьПараметр("СвойствоЮрАдрес", СвойствоЮрАдресСсылка);

Подведем итоги

Для эффективной работы с дополнительными свойствами объектов в 1С придерживайтесь следующих правил:

← На главную