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