Работа с запросами — это фундамент разработки на платформе 1С:Предприятие. Однако даже в самых простых конструкциях начинающие разработчики часто сталкиваются с ситуацией, когда запрос в консоли отрабатывает идеально, а в программном коде выдает ошибку «Переменная не определена» или возвращает пустое значение. Проанализируем типичную ситуацию на примере получения нового кода для справочника и разберем, как сделать этот процесс надежным и безопасным.
Рассмотрим исходный код, который часто становится причиной недоумения. Разработчик пытается получить максимальный код из справочника, прибавить к нему единицу и вернуть результат. На первый взгляд, логика верна, но в коде пропущен критически важный шаг взаимодействия с объектом ВыборкаИзРезультатаЗапроса.
Выясним причину: когда мы вызываем метод Выбрать(), система создает объект выборки, но указатель (курсор) в этот момент находится перед первой записью. Если мы попытаемся сразу обратиться к полю Выборка.НовыйКод, система выдаст ошибку, так как текущая строка еще не определена.
Для исправления ситуации необходимо использовать метод Следующий(). Этот метод выполняет сразу две функции: перемещает указатель на следующую (в данном случае — на первую и единственную) запись и возвращает Истина, если запись существует.
Проанализируем исправленный вариант функции:
Функция НовыйКод()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МАКСИМУМ(СКУД_Персонал.Код) + 1 КАК НовыйКод
|ИЗ
| Справочник.СКУД_Персонал КАК СКУД_Персонал";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// Обязательный переход к первой строке результата
Если Выборка.Следующий() Тогда
Возврат Выборка.НовыйКод;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
Рассмотрим ситуацию глубже. Даже если код стал рабочим, он таит в себе серьезную опасность для реальной информационной базы, в которой работают хотя бы два пользователя одновременно. Представим, что два бухгалтера одновременно нажимают кнопку создания новой карточки персонала.
МАКСИМУМ(Код), равный 100, и вычисляет 101.Именно об этом предупреждают опытные разработчики. Использование конструкции МАКСИМУМ + 1 вручную — это плохая практика для многопользовательских систем. Посмотрим на правильные альтернативы.
Для обеспечения уникальности и стабильной работы системы рекомендуется использовать встроенные механизмы платформы. Разберем основные способы.
Способ 1. Метод УстановитьНовыйКод()
Это наиболее предпочтительный метод. Платформа 1С берет на себя все сложности: учитывает префиксы организации, префиксы узлов распределенной информационной базы (РИБ) и блокирует таблицу номеров на время генерации, что исключает дублирование.
НовыйОбъект = Справочники.СКУД_Персонал.СоздатьЭлемент();
// Платформа сама найдет максимум и добавит 1 с учетом префиксов
НовыйОбъект.УстановитьНовыйКод();
НовыйОбъект.Записать();
Способ 2. Использование автоматической нумерации
В свойствах справочника в конфигураторе можно установить флаг «Автонумерация». В этом случае код будет присвоен автоматически в момент записи объекта, если он не был заполнен вручную.
Вернемся к нашему запросу. Что произойдет, если в справочнике еще нет ни одной записи? Функция МАКСИМУМ(Код) вернет значение NULL. В языке запросов 1С любая математическая операция с NULL (например, NULL + 1) также дает результат NULL. В итоге ваша функция вернет «пустоту» даже для первого элемента.
Проанализируем, как сделать запрос более отказоустойчивым с помощью функции ЕСТЬNULL:
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(МАКСИМУМ(СКУД_Персонал.Код), 0) + 1 КАК НовыйКод
|ИЗ
| Справочник.СКУД_Персонал КАК СКУД_Персонал";
В данном примере, если справочник пуст, функция ЕСТЬNULL заменит NULL на 0, после чего прибавление единицы даст корректный первый номер.
Посмотрим на еще один «подводный камень». В 1С коды справочников чаще всего имеют тип Строка. Это сделано для поддержки префиксов (например, "ЦБ-001").
Важно помнить: функция МАКСИМУМ для строк работает по правилам алфавитной сортировки, а не числовой. Если у вас есть коды "9" и "10", то "9" будет считаться больше, чем "10", потому что символ "9" идет позже символа "1".
Если вы вынуждены использовать запросы для нумерации строковых кодов, убедитесь, что:
Когда мы используем МАКСИМУМ в запросе, СУБД должна быстро найти самое большое значение. Чтобы этот запрос не «тормозил» на базе из миллиона записей, поле Код должно быть индексировано. В стандартных справочниках 1С поле Код индексируется автоматически, но если вы используете произвольный реквизит для своей нумерации, обязательно проверьте свойство «Индексировать» в конфигураторе.
Подведем итог. Чтобы избежать ошибок в «простейших запросах», всегда проверяйте результат метода Следующий(), обрабатывайте возможные NULL через ЕСТЬNULL и, по возможности, доверяйте генерацию кодов стандартному методу УстановитьНовыйКод().