В практике разработки на платформе 1С:Предприятие 8 часто возникает вопрос: насколько корректно получать данные, обращаясь к реквизитам через «точку» (разыменование ссылок)? Этот метод кажется интуитивно понятным и простым, однако за ним скрываются механизмы, которые могут существенно повлиять на производительность системы и стабильность кода. В этой статье мы подробно разберем, как работает обращение через точку в запросах и в программном коде, когда это допустимо, а когда стоит использовать альтернативные методы.
Для начала проанализируем, что происходит «под капотом» платформы, когда мы пишем запрос с обращением через точку. Рассмотрим пример кода из обсуждения:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| СчетНаОплатуПокупателю.ДоговорКонтрагента.бит_стр_Строительство.бит_стр_Проект КАК Проект
|ИЗ
| Документ.СчетНаОплатуПокупателю КАК СчетНаОплатуПокупателю
|ГДЕ
| СчетНаОплатуПокупателю.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Основание);
Когда этот запрос передается на уровень СУБД (SQL Server, PostgreSQL и др.), платформа 1С автоматически преобразует каждое обращение через точку в ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). В данном примере будет создано как минимум три соединения: со справочником договоров, затем с таблицей, на которую ссылается реквизит бит_стр_Строительство, и, наконец, с таблицей проектов.
Важные выводы из этого механизма:
LEFT JOIN, если на любом этапе цепочки встретится пустая ссылка или значение NULL, итоговый результат также будет NULL. Это поведение безопасно и не вызывает исключительных ситуаций в самом запросе.Проанализируем ситуацию, когда один из реквизитов в цепочке имеет составной тип данных. Это критический момент для производительности. Если реквизит может содержать ссылки, например, на 10 различных видов документов, то обращение через точку без уточнения типа заставит платформу выполнить LEFT JOIN со всеми 10 таблицами одновременно.
Чтобы избежать колоссальной нагрузки на СУБД, необходимо использовать оператор ВЫРАЗИТЬ. Посмотрим на примере, как ограничить выборку конкретным типом:
// Предположим, ДоговорКонтрагента имеет составной тип
Запрос.Текст = "ВЫБРАТЬ
| ВЫРАЗИТЬ(Счет.ДоговорКонтрагента КАК Справочник.ДоговорыКонтрагентов).Код КАК КодДоговора
|ИЗ
| Документ.СчетНаОплатуПокупателю КАК Счет";
Использование ВЫРАЗИТЬ сообщает платформе, что соединение нужно строить только с одной конкретной таблицей. Если тип значения в базе не совпадет с указанным в скобках, запрос вернет NULL, что гораздо лучше, чем перегрузка сервера лишними соединениями. Для автоматического выявления таких мест в коде подойдёт обработка для проверки запросов на разыменование составных полей.
Если нам нужно получить значение реквизита в программном коде (на языке 1С), а не внутри сложного запроса, рассмотрим использование функций Библиотеки Стандартных Подсистем (БСП). В модуле ОбщегоНазначения существуют специальные методы для этих целей. Для быстрого поиска готовых конструкций и функций библиотеки пригодится справочник по методам БСП с примерами вызова.
Разберем основные преимущества метода ОбщегоНазначения.ЗначениеРеквизитаОбъекта():
Пример использования функции БСП:
// Получение одного значения
Проект = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Основание, "ДоговорКонтрагента.бит_стр_Строительство.бит_стр_Проект");
// Массовое получение (рекомендуется для списков)
СтруктураРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СсылкаНаОбъект, "Организация, Склад, ВалютаДокумента");
Важное уточнение: Если вам нужно получить данные для списка объектов (например, в цикле при обработке строк), никогда не вызывайте получение реквизитов в цикле. Вместо этого используйте метод ЗначенияРеквизитовОбъектов() (во множественном числе), который выполнит один запрос ко всем ссылкам сразу.
Выясним причину, по которой крайне не рекомендуется использовать метод ПолучитьОбъект() для простого чтения реквизитов. Рассмотрим плохой пример:
// НЕПРАВИЛЬНО:
ИмяПроекта = СсылкаНаСчет.ПолучитьОбъект().ДоговорКонтрагента.бит_стр_Проект;
Почему это плохо:
ПолучитьОбъект() считывает абсолютно все данные объекта из базы данных, включая табличные части. Если у документа 1000 строк, они все будут загружены в память.Всегда отдавайте предпочтение запросам или функциям ОбщегоНазначения, если объект не требуется для изменения и записи.
Проанализируем ситуацию с точки зрения архитектурных стандартов 1С. Выбор способа получения данных зависит от контекста задачи:
Когда использовать: При подготовке данных для отчетов, динамических списков или проведении документов, когда данные нужны массово.
Ограничения: Не делайте цепочки длиннее 3-4 колен. Если цепочка становится слишком сложной, лучше использовать явное ЛЕВОЕ СОЕДИНЕНИЕ в конструкторе запроса — это сделает ваш код более читаемым для других разработчиков.
Когда использовать: В программном коде для получения 1-2 значений, когда написание полноценного запроса кажется избыточным, или когда важна защита от пустых ссылок.
Когда использовать: Допустимо только в простых сценариях «на лету», если вы абсолютно уверены, что типы не составные, а объем данных крайне мал (например, в формах при интерактивной работе пользователя). Однако помните, что каждое такое обращение — это неявный и не всегда оптимальный запрос к базе данных.
Подводя итог нашему анализу, сформулируем основные правила работы с реквизитами через точку:
ВЫРАЗИТЬ(Поле КАК Тип), чтобы ограничить количество соединений на уровне SQL.ОбщегоНазначения, чтобы избежать падений системы при обращении к «битым» ссылкам.NULL даже при наличии прав на основной объект.Соблюдение этих несложных правил позволит вам писать не только работающий, но и высокопроизводительный код, который будет легко поддерживать и масштабировать.