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