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