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