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