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