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