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