Пустое значение в коде 1С 8.3: Неопределено, Null, пустая строка, ссылка и коллекция

· 10 мин

Содержание

Чтобы проверить на пустоту значение в 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

Пустой результат запроса

В коде результат проверяют методом Пустой() — до выгрузки и обхода:

Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
    Возврат;
КонецЕсли;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
    // ...
КонецЦикла;

Ошибки из-за пустых значений и как их отладить

Почти все ошибки по теме сводятся к тому, что код ждал объект или число, а получил пустоту.

Диагностика: выберите симптом

Как найти, что именно пустое

  1. Поставьте точку останова на строке с ошибкой (F9 в Конфигураторе или в EDT).
  2. Запустите отладку и повторите действие пользователя.
  3. Выделите переменную и откройте Вычислить выражение (Shift+F9). Посмотрите не только значение, но и тип: в окне видно Неопределено, Null или конкретный тип ссылки.
  4. Для длинных цепочек через точку вычисляйте по частям: Объект.Договор, затем Объект.Договор.Владелец.

Проверка заполнения без кода

Для обязательных реквизитов объекта не обязательно писать проверки руками. В свойствах реквизита в Конфигураторе есть «Проверка заполнения» со значением «Выдавать ошибку» — платформа сама не даст записать или провести объект с пустым полем.

Если правило сложнее (поле обязательно только для одного вида операции), используйте обработчик модуля объекта:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Если ВидОперации <> Перечисления.ВидыОперацийПоступление.Товары Тогда
        Индекс = ПроверяемыеРеквизиты.Найти("Склад");
        Если Индекс <> Неопределено Тогда
            ПроверяемыеРеквизиты.Удалить(Индекс);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Перечисление и вид операции в примере условные: подставьте объекты своей конфигурации. В типовых конфигурациях правьте код через расширение, а не снимая конфигурацию с поддержки — так ваши проверки переживут обновление.

Частые вопросы

Чем отличается Неопределено от Null в 1С?
Неопределено — значение не задано в коде или в реквизите составного типа. Null — значение отсутствует в данных, обычно приходит из запроса. Они не равны друг другу, но ЗначениеЗаполнено() считает пустыми оба.
Почему условие Поле = NULL в запросе ничего не находит?
В языке запросов любое сравнение с NULL через знак равенства даёт не Истину, а неизвестный результат. Используйте конструкцию Поле ЕСТЬ NULL или НЕ Поле ЕСТЬ NULL.
Можно ли проверить на пустоту табличную часть одной функцией?
Для проверки «есть ли строки» используйте Объект.Товары.Количество() = 0. Пустые ячейки внутри строк нужно проверять обходом строк или через флаг «Проверка заполнения» у реквизитов табличной части.
Как проверить, что переменная вообще была инициализирована?
Сравните её с Неопределено: Если Переменная = Неопределено Тогда. Новая переменная, которой ничего не присвоили, имеет именно это значение.
ЗначениеЗаполнено работает на клиенте?
Да, функция доступна и на клиенте, и на сервере. Но если на клиенте проверять реквизит через точку от ссылки, это вызовет серверный вызов — такие данные лучше получить заранее на сервере.