Где проверять обязательный параметр в 1С: в обработчике команды или перед запросом?
Разработка - Рефакторинг и качество кода
Когда нескольких строк BSL недостаточно
Допустим, во внешней обработке есть поле «Код» и две команды: «Выполнить» и «Повторить запрос».
Обе команды используют одну серверную функцию. По новому требованию, если код не указан, запрос выполнять нельзя.
Разработчик добавляет проверку в обработчик кнопки «Выполнить». При пустом поле появляется сообщение, запрос не запускается. Кажется, задача решена.
Но вторая команда продолжает вызывать ту же серверную функцию без проверки.
Получается, что одно и то же ограничение действует по-разному в зависимости от способа запуска.
Разберём, как исправить эту ситуацию.
1. Подготовка внешней обработки
Пример рассчитан на управляемое приложение платформы 1С:Предприятие 8.3.
Создадим внешнюю обработку и добавим управляемую форму.
В редакторе формы необходимо выполнить следующие действия:
-
Создать реквизит формы
КодтипаСтрока. Это именно реквизит формы, а не реквизит объекта внешней обработки. -
Разместить на форме поле ввода и связать его с реквизитом
Код. -
Создать команду формы
Выполнитьи назначить ей действие — клиентский обработчикВыполнить. -
Создать команду формы
ПовторитьЗапроси назначить ей действие — клиентский обработчикПовторитьЗапрос. -
Разместить на форме две кнопки и связать каждую с соответствующей командой.
После этого в модуле формы должны существовать обработчики обеих команд.
Для примера будем считать, что Код всегда имеет тип Строка. Пустая строка и строка из обычных пробелов считаются недопустимыми.
Другие требования к коду — длина, формат, существование в базе — здесь не рассматриваются.
2. Ошибочный вариант: проверка только в одной команде
Сначала рассмотрим код, который не следует использовать как окончательное решение.
&НаКлиенте
Процедура Выполнить(Команда)
Если СокрЛП(Код) = "" Тогда
Сообщить("Укажите код");
Возврат;
КонецЕсли;
Количество = ПолучитьКоличествоПоКоду(Код);
Сообщить("Найдено: " + Строка(Количество));
КонецПроцедуры
При нажатии кнопки «Выполнить» проверка сработает.
Но вторая команда может выглядеть так:
&НаКлиенте
Процедура ПовторитьЗапрос(Команда)
Количество = ПолучитьКоличествоПоКоду(Код);
Сообщить("Найдено: " + Строка(Количество));
КонецПроцедуры
Она не проверяет значение перед вызовом.
Если серверная функция также не контролирует обязательность параметра, требование можно обойти через вторую кнопку.
Ошибка здесь не в условии СокрЛП(Код) = "". Для нашего строкового правила оно подходит.
Ошибка в том, что проверка размещена только на одном пути выполнения.
3. Определяем место обязательной проверки
Прежде чем менять код, нужно ответить на вопрос: к чему относится ограничение?
Если код обязателен только для конкретного действия пользователя, проверка может находиться в обработчике этого действия.
Если же запрос нельзя выполнять без кода независимо от того, кто его вызвал, обязательное условие должно проверяться в общей операции.
В нашем случае действует второе правило.
Поэтому проверку нужно разместить внутри серверной функции перед выполнением запроса.
Для удобства пользователя можно оставить и предварительную проверку на клиенте. Но она не должна быть единственной.
4. Полный исправленный код модуля формы
Ниже приведён единый пример для описанной управляемой формы.
Чтобы не зависеть от прикладных объектов конкретной конфигурации, серверная функция формирует таблицу значений с двумя строками и передаёт её в запрос. Запрос считает строки, у которых значение поля Код совпадает с переданным параметром.
Таким образом, пример показывает именно выполнение запроса с параметром, но не требует наличия справочника Номенклатура.
&НаКлиенте
Процедура Выполнить(Команда)
ВыполнитьОперацию();
КонецПроцедуры
&НаКлиенте
Процедура ПовторитьЗапрос(Команда)
ВыполнитьОперацию();
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьОперацию()
Если СокрЛП(Код) = "" Тогда
Сообщить("Укажите код");
Возврат;
КонецЕсли;
Количество = ПолучитьКоличествоПоКоду(Код);
Сообщить("Найдено: " + Строка(Количество));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьКоличествоПоКоду(Знач Код)
Если СокрЛП(Код) = "" Тогда
ВызватьИсключение "Укажите код";
КонецЕсли;
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Код");
СтрокаТаблицы = Таблица.Добавить();
СтрокаТаблицы.Код = "TEST001";
СтрокаТаблицы = Таблица.Добавить();
СтрокаТаблицы.Код = "TEST002";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК Количество
|ИЗ
| &Таблица КАК Данные
|ГДЕ
| Данные.Код = &Код";
Запрос.УстановитьПараметр("Таблица", Таблица);
Запрос.УстановитьПараметр("Код", Код);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Количество;
КонецЕсли;
Возврат 0;
КонецФункции
Что изменилось
Обе команды теперь вызывают общую клиентскую процедуру ВыполнитьОперацию().
Она проверяет поле и сообщает пользователю о необходимости заполнения до серверного вызова.
Серверная функция ПолучитьКоличествоПоКоду() выполняет собственную проверку. Поэтому её нельзя заставить выполнить запрос с пустым кодом простым обходом клиентского обработчика.
Для функции используется &НаСервереБезКонтекста, поскольку она не обращается к реквизитам формы напрямую, а получает значение через параметр.
Из серверной функции на клиент возвращается число. Объект РезультатЗапроса через границу клиент–сервер не передаётся.
5. Почему проверка выполняется дважды
На первый взгляд две одинаковые проверки выглядят лишними.
Но здесь у них разные назначения.
Клиентская проверка позволяет сразу показать сообщение и не выполнять ненужный серверный вызов.
Серверная проверка обеспечивает условие самой операции.
Если в дальнейшем появится третья команда или другой предусмотренный путь вызова серверной функции, обязательное условие останется внутри неё.
При этом серверная функция проверяет именно то значение, которое получила в параметре. Она не полагается на то, что клиентская проверка уже выполнялась.
6. Почему используется СокрЛП(), а не ЗначениеЗаполнено()
В платформе есть функция ЗначениеЗаполнено(). Она полезна, когда стандартные правила заполненности соответствуют задаче.
Однако для разных типов данных эти правила могут отличаться от требований конкретного приложения.
Например, числовой ноль иногда является допустимым значением, хотя стандартная проверка заполненности может трактовать его как незаполненное.
В нашем примере условие сформулировано точно: код имеет строковый тип, а пустая строка и строка из обычных пробелов недопустимы.
Поэтому используется выражение:
СокрЛП(Код) = ""
Если потребуется учитывать табуляцию, неразрывные пробелы или дополнительные ограничения, проверку нужно изменить.
Не стоит автоматически заменять одно правило другим только потому, что какая-то функция привычнее.
7. Проверка результата
После добавления кода в модуль формы можно выполнить следующие сценарии.
Проверка 1. Пустой код.
Оставляем поле пустым и нажимаем «Выполнить».
Ожидаемый результат: сообщение «Укажите код». Серверная функция не вызывается.
Проверка 2. Строка из пробелов.
Вводим несколько обычных пробелов.
Ожидаемый результат: то же сообщение, запрос не выполняется.
Проверка 3. Вторая команда.
Оставляем код пустым и нажимаем «Повторить запрос».
Ожидаемый результат: предварительная проверка срабатывает так же, как для первой команды.
Проверка 4. Первый существующий код.
Вводим TEST001.
Ожидаемый результат: сообщение «Найдено: 1».
Проверка 5. Второй существующий код.
Вводим TEST002.
Ожидаемый результат: сообщение «Найдено: 1».
Проверка 6. Несуществующий код.
Вводим TEST999.
Ожидаемый результат: сообщение «Найдено: 0».
Проверка 7. Серверное предусловие.
В отладочном сценарии вызываем серверную функцию с пустой строкой, минуя предварительную клиентскую проверку.
Ожидаемый результат: возникает исключение до выполнения запроса.
Эта проверка важна: она показывает, что ограничение находится внутри операции, а не только в интерфейсе.
Перечисленные результаты являются ожидаемыми. Они не представлены как результаты фактически проведённого тестирования.
8. Что делать с серверными исключениями
В примере серверная функция использует ВызватьИсключение, если нарушено обязательное условие.
При обычной работе через две кнопки пустое значение перехватывается предварительной клиентской проверкой.
Если же серверная функция вызывается без неё, исключение будет передано вызывающему коду.
В промышленной обработке нужно отдельно определить, как обрабатывать ожидаемые ошибки ввода и непредвиденные технические сбои.
Не следует без разбора перехватывать все исключения и выводить пользователю ОписаниеОшибки(). Такой подход может скрыть реальную проблему и показать технические сведения, не предназначенные для пользователя.
Для небольшого учебного примера достаточно явно зафиксировать это ограничение.
9. Когда проверку не нужно переносить на сервер
Рассмотренный подход подходит не для любой ситуации.
Предположим, одна команда ищет элемент по указанному коду, а другая при пустом коде должна возвращать все элементы.
В таком случае пустой код не является ошибкой общей операции.
Если безусловно запретить его внутри серверной функции, можно нарушить существующее поведение.
Поэтому перед переносом проверки нужно установить, действительно ли параметр обязателен для самой операции.
Если да — правило должно обеспечиваться внутри неё.
Если нет — проверка может оставаться на уровне конкретного пользовательского сценария.
Заключение
В 1С важно не только написать правильное условие, но и выбрать место его выполнения.
Если одна операция вызывается несколькими командами, проверка только в обработчике одной кнопки может оказаться недостаточной.
В рассмотренном примере обе команды используют общую клиентскую процедуру, а серверная функция самостоятельно контролирует обязательность параметра перед запросом.
Это позволяет не повторять код в обработчиках и не зависеть от того, каким способом запущена операция.
Главное — определить, кому принадлежит правило: интерфейсу или самой операции.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.