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