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