Как правильно сравнить значение с "Неопределено" в 1С:Предприятии и избежать ошибок?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← К списку

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

Что такое "Неопределено" и когда оно возникает?

Прежде всего, выясним, что представляет собой тип Неопределено. Это специальный тип данных в 1С:Предприятии, который обозначает отсутствие какого-либо конкретного значения, не принадлежащего ни к одному другому типу. Важно отметить, что Неопределено является не только типом, но и единственным значением этого типа.

Рассмотрим подробнее ситуации, когда мы можем встретиться со значением Неопределено:

  1. Переменные без присвоенного значения: Если мы объявили переменную с помощью оператора Перем, но еще не присвоили ей никакого значения, она будет иметь тип и значение Неопределено.
  2. Реквизиты составного типа: Когда реквизит какого-либо объекта (например, справочника, документа) имеет составной тип данных (то есть может хранить значения нескольких разных типов), то по умолчанию, до присвоения конкретного значения, этот реквизит также будет иметь значение Неопределено.
  3. Результат функций: Многие встроенные функции платформы возвращают Неопределено, если они не смогли выполнить свою задачу или вернуть запрошенный результат. Например, при неудачном поиске элемента или некорректных входных параметрах.
  4. Получение объекта по несуществующей ссылке: Если мы пытаемся получить объект из информационной базы по ссылке (например, с помощью метода ПолучитьОбъект()), но объект с такой ссылкой фактически не существует (например, был удален), то результатом этой операции будет Неопределено.

Прямое сравнение с "Неопределено"

Самым простым, понятным и рекомендуемым способом проверки значения на Неопределено является прямое сравнение.

Мы используем операторы сравнения = (равно) или <> (не равно) непосредственно со значением Неопределено. Это проверяет, является ли переменная именно этим специальным значением.

Посмотрим на пример:


Перем МояПеременная; // МояПеременная сейчас имеет значение Неопределено

Если МояПеременная = Неопределено Тогда
    Сообщить("Переменная не определена.");
КонецЕсли;

МояПеременная = "Какое-то значение";

Если МояПеременная <> Неопределено Тогда
    Сообщить("Переменная содержит значение.");
КонецЕсли;

Также существует альтернативный подход, который может ввести в заблуждение, если не понимать его сути: сравнение типа значения с типом Неопределено. Мы можем использовать функцию ТипЗнч() для получения типа значения переменной и сравнить его с объектом типа, полученным через Тип("Неопределено").

Разберем разницу: Тип("Неопределено") возвращает не само значение Неопределено, а объект типа Тип, который описывает тип "Неопределено".

Пример такого сравнения:


Перем МояПеременная;

Если ТипЗнч(МояПеременная) = Тип("Неопределено") Тогда
    Сообщить("Тип значения переменной - Неопределено.");
КонецЕсли;

Оба этих подхода допустимы, но прямое сравнение Объект = Неопределено часто считается более интуитивным и является стандартом в большинстве случаев, поскольку оно проверяет именно значение, а не его тип как объект.

Отличие "Неопределено" от "Null" и пустых значений других типов

Очень важно четко различать Неопределено от других похожих состояний, таких как Null и пустые значения различных типов. Давайте проанализируем эти различия:

  1. Null: Это значение в основном встречается при работе с запросами к базе данных, особенно при использовании левых или правых соединений, когда для связанных таблиц отсутствуют соответствующие записи. Null обозначает отсутствие значения в выборке. Во встроенном языке 1С Null используется крайне редко, но в запросах его часто необходимо обрабатывать с помощью оператора ЕСТЬNULL.
  2. Пустые значения других типов: Для каждого базового типа данных существует "пустое" или "значение по умолчанию". Например:
    • Для числового типа это 0.
    • Для строкового типа это "" (пустая строка).
    • Для типа Дата это Дата(1,1,1).
    • Для ссылочных типов (справочники, документы) это пустая ссылка (например, Справочники.МойСправочник.ПустаяСсылка()).

    В отличие от этих значений, которые являются полноценными значениями своего типа, Неопределено означает отсутствие значения какого-либо определенного типа.

Таким образом, Неопределено — это не ноль, не пустая строка и не пустая ссылка. Это принципиально другое состояние, указывающее на отсутствие значения вообще.

Функция ЗначениеЗаполнено() и "Неопределено"

Функция ЗначениеЗаполнено() в 1С:Предприятии предназначена для проверки, содержит ли переменная непустое значение, характерное для своего типа. Например, для строки она вернет Истина, если строка содержит непробельные символы, и Ложь, если строка пустая или состоит только из пробелов.

Как же эта функция взаимодействует с Неопределено? Для значений типа Неопределено и Null функция ЗначениеЗаполнено() всегда возвращает Ложь.

Посмотрим на пример:


Перем МояСтрока;
Перем МояСсылка;
Перем МоеЧисло;
Перем МоеНеопределенноеЗначение;

МояСтрока = ""; // Пустая строка
МояСсылка = Справочники.Пользователи.ПустаяСсылка(); // Пустая ссылка
МоеЧисло = 0; // Ноль
// МоеНеопределенноеЗначение остается Неопределено

Сообщить("Строка заполнена: " + ЗначениеЗаполнено(МояСтрока)); // Ложь
Сообщить("Ссылка заполнена: " + ЗначениеЗаполнено(МояСсылка)); // Ложь
Сообщить("Число заполнено: " + ЗначениеЗаполнено(МоеЧисло)); // Ложь
Сообщить("Неопределенное значение заполнено: " + ЗначениеЗаполнено(МоеНеопределенноеЗначение)); // Ложь

МояСтрока = "Привет";
МоеЧисло = 10;
Сообщить("Строка заполнена: " + ЗначениеЗаполнено(МояСтрока)); // Истина
Сообщить("Число заполнено: " + ЗначениеЗаполнено(МоеЧисло)); // Истина

Таким образом, хотя ЗначениеЗаполнено() возвращает Ложь для Неопределено, она не является полноценной заменой для прямого сравнения с Неопределено. Мы используем ее для проверки заполненности других типов данных, где уже исключена возможность значения Неопределено, или в комбинации с проверкой на Неопределено для более комплексной валидации.

Проверка существования объекта по ссылке

Одной из частых задач является проверка, существует ли физически объект в базе данных по имеющейся у нас ссылке. Ссылка может быть "битой" (устаревшей), если объект был удален. В этом случае попытка получить объект по такой ссылке вернет Неопределено. Рассмотрим несколько способов решения этой задачи.

  1. Использование метода ПолучитьОбъект()

    Этот способ является одним из наиболее распространенных и удобных, особенно когда нам не просто нужно узнать о существовании объекта, но и сразу получить его для дальнейшей работы (модификации, записи и т.д.).

    Мы пытаемся получить объект по ссылке. Если объект существует, метод ПолучитьОбъект() вернет нам его. Если же объект с такой ссылкой в базе данных отсутствует, метод вернет Неопределено.

    Посмотрим на пример использования:

    
    // Предположим, у нас есть переменная СсылкаНаДокумент
    // СсылкаНаДокумент = Документы.РеализацияТоваровУслуг.НайтиПоНомеру("000000001", Дата(2023,1,1));
    
    Если СсылкаНаДокумент = Неопределено Тогда
        Сообщить("Ссылка не найдена или не задана.");
        Возврат;
    КонецЕсли;
    
    // Попытаемся получить объект по ссылке
    ОбъектДокумент = СсылкаНаДокумент.ПолучитьОбъект();
    
    Если ОбъектДокумент = Неопределено Тогда
        Сообщить("Объект по ссылке не существует в базе данных. Вероятно, он был удален.");
        // Здесь мы можем, например, создать новый документ,
        // если нам нужно восстановить данные или создать новый на основе старой ссылки.
        // ОбъектДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
        // ОбъектДокумент.УстановитьСсылкуНового(СсылкаНаДокумент); // Если нужно сохранить ту же ссылку
    Иначе
        Сообщить("Объект успешно получен: " + ОбъектДокумент.Представление());
        // Мы можем работать с ОбъектДокумент
        // ОбъектДокумент.Комментарий = "Изменен после проверки";
        // ОбъектДокумент.Записать();
    КонецЕсли;
    

    Преимущества: Мы сразу получаем готовый к работе объект, если он существует.

    Недостатки: Метод ПолучитьОбъект() может быть менее производительным, чем проверка запросом, особенно если ссылка не "битая". Платформа выделяет ресурсы для создания полной копии объекта в памяти, даже если нам нужен был только факт его существования. Это может быть неэффективно при проверке большого количества ссылок.

  2. Проверка запросом

    Использование запроса для проверки существования ссылки может быть более эффективным с точки зрения производительности, особенно если нам нужно проверить множество ссылок или если объект целиком не требуется получать в память. Запрос позволяет выбрать только необходимую информацию (например, есть ли запись с таким УникальнымИдентификатором) и избежать считывания всех полей объекта.

    Приведем пример структуры такого запроса:

    
    Функция СсылкаСуществуетЗапросом(Знач СсылкаОбъекта)
    
        Если ТипЗнч(СсылкаОбъекта) = Тип("Неопределено") Тогда
            Возврат Ложь;
        КонецЕсли;
    
        Запрос = Новый Запрос;
        Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    ИСТИНА КАК Существует
        |ИЗ
        |    " + СсылкаОбъекта.Метаданные().ПолноеИмя() + " КАК МойОбъект
        |ГДЕ
        |    МойОбъект.Ссылка = &Ссылка";
    
        Запрос.УстановитьПараметр("Ссылка", СсылкаОбъекта);
    
        Результат = Запрос.Выполнить().Выбрать();
    
        Возврат Результат.Следующий();
    
    КонецФункции
    
    // Использование:
    // Перем МояСсылка = Документы.РасходнаяНакладная.ПолучитьСсылку(Новый УникальныйИдентификатор("..."));
    // Если СсылкаСуществуетЗапросом(МояСсылка) Тогда
    //     Сообщить("Объект по ссылке существует.");
    // Иначе
    //     Сообщить("Объект по ссылке не найден.");
    // КонецЕсли;
    

    Мы видим, что запрос выбирает только один признак существования, что минимизирует нагрузку.

  3. Функция ОбщегоНазначения.СсылкаСуществует() из БСП

    Если в вашей конфигурации используется Библиотека стандартных подсистем (БСП), то мы можем воспользоваться готовой, оптимизированной и стандартизированной функцией ОбщегоНазначения.СсылкаСуществует(). Эта функция предназначена именно для проверки физического наличия записи в информационной базе по переданному значению ссылки и возвращает Истина, если запись существует, и Ложь в противном случае.

    Это самый удобный и рекомендуемый способ, если БСП доступна. Он инкапсулирует логику запроса и других проверок, предоставляя простой интерфейс.

    Пример использования:

    
    // Предположим, у нас есть переменная СсылкаНаЭлементСправочника
    // СсылкаНаЭлементСправочника = Справочники.Номенклатура.НайтиПоКоду("00001");
    
    Если Тип("ОбщегоНазначения") <> Тип("Неопределено") Тогда // Проверяем доступность модуля БСП
        Если ОбщегоНазначения.СсылкаСуществует(СсылкаНаЭлементСправочника) Тогда
            Сообщить("Элемент справочника по ссылке существует.");
        Иначе
            Сообщить("Элемент справочника по ссылке не найден.");
        КонецЕсли;
    Иначе
        Сообщить("Модуль ОбщегоНазначения недоступен, используйте другие методы проверки.");
    КонецЕсли;
    

    Когда какой вариант использовать?

    • Если нам необходимо получить сам объект для его дальнейшей обработки или модификации, и мы не проверяем очень большое количество ссылок, то метод Ссылка.ПолучитьОбъект() будет наиболее удобным.
    • Если нам нужен только факт существования объекта, и мы хотим минимизировать нагрузку на систему, или если мы проверяем множество ссылок, то более предпочтительными будут проверка запросом или использование функции ОбщегоНазначения.СсылкаСуществует() из БСП.

Надеемся, что этот подробный разбор поможет вам уверенно работать со значением Неопределено в 1С:Предприятии и создавать более надежные и эффективные решения!

← К списку