Пустое значение в коде 1С 8.3: Неопределено, Null, пустая строка, ссылка и коллекция
Содержание
Чтобы проверить на пустоту значение в 1С, в большинстве задач хватает одной функции: ЗначениеЗаполнено(Значение). Она возвращает Ложь для Неопределено, Null, пустой строки, нуля, пустой даты и пустой ссылки. Для строк с пробелами надёжнее ПустаяСтрока(), для коллекций — Количество() = 0, а в запросе — ЕСТЬ NULL и сравнение с ЗНАЧЕНИЕ(...ПустаяСсылка).
Типичная ситуация: разработчик дописывает обработку заполнения документа, и на тестовой базе всё работает. А у бухгалтера падает ошибка Значение не является значением объектного типа, потому что у одного контрагента не заполнен договор. Ниже — какие бывают виды пустоты в 1С:Предприятии 8.3, чем их проверять и где проверка чаще всего ломается.
Какие бывают «пустые» значения в платформе 1С
В языке 1С нет одного универсального «ничего». Есть несколько разных состояний, и путать их — главная причина ошибок.
| Значение | Что означает | Где появляется |
|---|---|---|
Неопределено | значение не задано вообще | новая переменная, пустой реквизит составного типа, Соответствие.Получить() без ключа |
Null | значение отсутствует в данных | результат запроса: левое соединение, реквизит через точку от пустой ссылки |
"" | пустая строка | реквизит типа Строка, ПрочитатьСтроку() |
0 | ноль | реквизит типа Число по умолчанию |
'00010101' | пустая дата | реквизит типа Дата по умолчанию, то же самое, что Дата(1, 1, 1) |
| пустая ссылка | ссылка на объект без самого объекта | реквизит ссылочного типа по умолчанию |
| пустая коллекция | объект есть, элементов нет | Новый Массив, пустая таблица значений |
Несколько правил, которые стоит держать в голове:
- 🔹
НеопределеноиNull— разные значения. ВыражениеНеопределено = NullдаётЛожь. - 🔹 Пустая ссылка — это не
Неопределено. У неё есть тип (например,СправочникСсылка.Контрагенты), просто она никуда не указывает. - 🔹 Пустая коллекция — не пустое значение. Переменная с
Новый Массивзаполнена объектом, в котором ноль элементов. - 🔹 Тип реквизита определяет «пустое» по умолчанию. Реквизит типа Число не может быть
Неопределено, а реквизит составного типа — может.
Тип значения проверяют через ТипЗнч():
Если ТипЗнч(Значение) = Тип("Неопределено") Тогда
// значение не задано
ИначеЕсли Значение = Null Тогда
// пришло из запроса без данных
КонецЕсли;
Универсальная проверка значения на пустоту: ЗначениеЗаполнено
ЗначениеЗаполнено() сравнивает значение со значением по умолчанию для его типа. Работает на клиенте и на сервере, не требует знать тип заранее.
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщить("Не указан контрагент");
Возврат;
КонецЕсли;
Что вернёт функция для разных значений:
| Выражение | Результат |
|---|---|
ЗначениеЗаполнено(Неопределено) | Ложь |
ЗначениеЗаполнено(Null) | Ложь |
ЗначениеЗаполнено("") | Ложь |
ЗначениеЗаполнено(0) | Ложь |
ЗначениеЗаполнено('00010101') | Ложь |
ЗначениеЗаполнено(Справочники.Контрагенты.ПустаяСсылка()) | Ложь |
ЗначениеЗаполнено(15) | Истина |
ЗначениеЗаполнено("ООО Ромашка") | Истина |
Где функция подводит:
- ⚠️ Ноль как допустимое значение. Количество 0 или скидка 0% — вполне реальные данные.
ЗначениеЗаполнено(0)вернётЛожь, и код посчитает поле незаполненным. Если ноль допустим, проверяйте тип иНеопределеноявно. - ⚠️ Булево. Не проверяйте флажки через
ЗначениеЗаполнено. Пишите прямо:Если Объект.Проведен Тогда. Так понятнее и без сюрпризов. - ⚠️ Битая ссылка. Если объект удалён из базы, а ссылка на него осталась в реквизите, функция вернёт
Истина: ссылка не пустая. Как отловить такой случай — ниже.
Одна строка Если Не ЗначениеЗаполнено(...) в начале процедуры заменяет три-четыре проверки по типам. Используйте её по умолчанию, а точечные методы — там, где важна разница между видами пустоты.
Пустая строка, число и дата: проверка примитивных типов
Строки
Обычное сравнение Строка = "" не ловит строку из пробелов. Пользователь ставит пробел в поле «Комментарий» — и проверка пропускает «заполненное» поле.
Для строк есть отдельная функция ПустаяСтрока(). Она возвращает Истина, если в строке нет значащих символов: пусто, пробелы, табуляция, переводы строки.
Если ПустаяСтрока(Объект.Комментарий) Тогда
Сообщить("Заполните комментарий");
КонецЕсли;
// эквивалент через сокращение пробелов
Если СокрЛП(Объект.Комментарий) = "" Тогда
// ...
КонецЕсли;
ПустаяСтрока() ждёт строку. Если в переменной может оказаться Неопределено (например, значение пришло из Структура или из файла), сначала проверьте тип:
Если ТипЗнч(Значение) <> Тип("Строка") Или ПустаяСтрока(Значение) Тогда
// пусто или не строка
КонецЕсли;
Числа
Для числа «пусто» — это ноль. Если ноль допустим, а важно отличить «не задано», храните признак отдельно или используйте реквизит составного типа, где пустое значение — Неопределено.
Если ТипЗнч(Количество) <> Тип("Число") Тогда
Количество = 0;
КонецЕсли;
Даты
Пустая дата в 1С — 1 января 0001 года, 00:00:00. Её записывают литералом '00010101' или конструктором Дата(1, 1, 1).
Если Объект.ДатаОплаты = Дата(1, 1, 1) Тогда
// дата не указана
КонецЕсли;
// то же самое короче
Если Не ЗначениеЗаполнено(Объект.ДатаОплаты) Тогда
// дата не указана
КонецЕсли;
Не сравнивайте дату с Неопределено. Реквизит типа Дата никогда не бывает Неопределено, такая проверка всегда даст Ложь.
Проверка ссылок на справочники и документы
Пустая ссылка
У каждого менеджера ссылочного объекта есть метод ПустаяСсылка(), а у самой ссылки — метод Пустая(). Три равнозначных варианта:
// 1. метод ссылки
Если Объект.Договор.Пустая() Тогда ...
// 2. сравнение с пустой ссылкой конкретного типа
Если Объект.Договор = Справочники.ДоговорыКонтрагентов.ПустаяСсылка() Тогда ...
// 3. универсально
Если Не ЗначениеЗаполнено(Объект.Договор) Тогда ...
Метод Пустая() работает только у ссылки. Если реквизит составного типа и в нём лежит Неопределено, вызов Неопределено.Пустая() упадёт с ошибкой. Поэтому для составных реквизитов берите ЗначениеЗаполнено().
Составной тип
В реквизите «Субконто», «Основание» или «Объект расчётов» может быть ссылка любого из нескольких типов или Неопределено. Сравнение с пустой ссылкой одного типа здесь не работает
: пустая ссылка на документ не равна пустой ссылке на справочник.
Если ЗначениеЗаполнено(Объект.ДокументОснование)
И ТипЗнч(Объект.ДокументОснование) = Тип("ДокументСсылка.СчетНаОплатуПокупателю") Тогда
// основание — счёт, и он указан
КонецЕсли;
Битая ссылка: «Объект не найден»
Ссылка заполнена, а объекта в базе нет — его удалили напрямую или не до конца загрузили обменом. В форме такое поле показывает <Объект не найден> с идентификатором.
ЗначениеЗаполнено() и Пустая() здесь не помогут — ссылка формально не пустая. Проверка — через получение объекта:
Если ЗначениеЗаполнено(Ссылка) И Ссылка.ПолучитьОбъект() = Неопределено Тогда
// ссылка битая
КонецЕсли;
ПолучитьОбъект() читает объект целиком из базы. В цикле по тысячам строк это медленно. Для массовой проверки используйте запрос (пример — в разделе про язык запросов).
Обращение через точку
Конструкция Объект.Договор.Владелец.ИНН при пустом договоре не упадёт: от пустой ссылки платформа вернёт пустые значения реквизитов. Но каждое обращение через точку читает объект из базы. Если реквизит нужен в цикле, получите его запросом заранее.
Пустой массив, список значений и таблица: работа с коллекциями
Коллекцию проверяют на пустоту по числу элементов. Метод Количество() есть у всех основных коллекций.
Если Массив.Количество() = 0 Тогда ...
Если СписокЗначений.Количество() = 0 Тогда ...
Если ТаблицаЗначений.Количество() = 0 Тогда ...
Если Объект.Товары.Количество() = 0 Тогда ... // табличная часть
Но сначала убедитесь, что сама коллекция существует. Если функция могла вернуть Неопределено вместо массива, вызов Количество() даст ошибку.
Если Результат = Неопределено Или Результат.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Порядок условий здесь важен: 1С вычисляет Или по сокращённой схеме и не дойдёт до Количество(), если первое условие уже истинно.
Структура и соответствие
У структуры проверяют не только «пустая ли она», но и есть ли нужный ключ. Метод Свойство() делает обе вещи сразу:
Значение = Неопределено;
Если Параметры.Свойство("Организация", Значение) И ЗначениеЗаполнено(Значение) Тогда
// ключ есть, значение заполнено
КонецЕсли;
Соответствие.Получить(Ключ) при отсутствии ключа возвращает Неопределено. Если в соответствии могут храниться и сами Неопределено, отсутствие ключа от пустого значения так не отличить — храните заглушку или проверяйте ключ перебором.
Пустые строки в таблице
Таблица может быть «непустой», но состоять из незаполненных строк. Для табличной части документа проверяют каждую строку:
Для Каждого Строка Из Объект.Товары Цикл
Если Не ЗначениеЗаполнено(Строка.Номенклатура) Тогда
Сообщить(СтрШаблон("Строка %1: не указана номенклатура",
Формат(Строка.НомерСтроки, "ЧГ=0")));
КонецЕсли;
КонецЦикла;
Пустые значения в языке запросов
В запросе своя логика пустоты. Главное отличие: Null в запросе нельзя сравнивать через =. Условие Поле = NULL не вернёт ни одной строки.
NULL и функция ЕСТЬNULL
Null появляется в двух случаях: левое соединение не нашло пару или реквизит берётся через точку от пустой ссылки. Проверяют его оператором ЕСТЬ NULL, а подставляют значение функцией ЕСТЬNULL():
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
ГДЕ
Остатки.Номенклатура ЕСТЬ NULL
Этот запрос вернёт номенклатуру без остатков, а в поле «Остаток» вместо Null будет 0. Без ЕСТЬNULL сложение такого поля в коде падает с ошибкой.
Регистр ТоварыНаСкладах в примере условный — подставьте регистр остатков своей конфигурации.
Пустая ссылка в запросе
Пустую ссылку передают через функцию ЗНАЧЕНИЕ() или параметром:
ГДЕ
Документ.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
Если поле может быть и пустой ссылкой, и Null (через левое соединение), проверяйте оба случая:
ГДЕ
(Таблица.Договор ЕСТЬ NULL
ИЛИ Таблица.Договор = ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка))
Пустая дата и пустая строка
ГДЕ
Документ.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
ИЛИ Документ.Комментарий = ""
Для строк неограниченной длины прямое сравнение запрещено — платформа выдаст ошибку о сравнении строк неограниченной длины. Обрежьте строку до фиксированной длины:
ГДЕ
ПОДСТРОКА(Документ.Комментарий, 1, 1) = ""
Битые ссылки запросом
Массово найти «Объект не найден» помогает проверка через точку: у несуществующего объекта представление и реквизиты в запросе приходят как Null.
ВЫБРАТЬ
Документ.Ссылка,
Документ.Контрагент
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Контрагент <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
И Документ.Контрагент.Наименование ЕСТЬ NULL
Пустой результат запроса
В коде результат проверяют методом Пустой() — до выгрузки и обхода:
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат;
КонецЕсли;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// ...
КонецЦикла;
Ошибки из-за пустых значений и как их отладить
Почти все ошибки по теме сводятся к тому, что код ждал объект или число, а получил пустоту.
Как найти, что именно пустое
- Поставьте точку останова на строке с ошибкой (
F9в Конфигураторе или в EDT). - Запустите отладку и повторите действие пользователя.
- Выделите переменную и откройте
Вычислить выражение(Shift+F9). Посмотрите не только значение, но и тип: в окне видноНеопределено,Nullили конкретный тип ссылки. - Для длинных цепочек через точку вычисляйте по частям:
Объект.Договор, затемОбъект.Договор.Владелец.
Проверка заполнения без кода
Для обязательных реквизитов объекта не обязательно писать проверки руками. В свойствах реквизита в Конфигураторе есть «Проверка заполнения» со значением «Выдавать ошибку» — платформа сама не даст записать или провести объект с пустым полем.
Если правило сложнее (поле обязательно только для одного вида операции), используйте обработчик модуля объекта:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если ВидОперации <> Перечисления.ВидыОперацийПоступление.Товары Тогда
Индекс = ПроверяемыеРеквизиты.Найти("Склад");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Перечисление и вид операции в примере условные: подставьте объекты своей конфигурации. В типовых конфигурациях правьте код через расширение, а не снимая конфигурацию с поддержки — так ваши проверки переживут обновление.