К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как проверить, ссылка или объект в 1С

Как в 1С определить, перед вами ссылка или объект: методы ТипЗнч, СсылкаСуществует, ПроверкаЗаполнения, примеры кода, типичные ошибки и границы применения.

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

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

Чем ссылка отличается от объекта в 1С

Ссылка (например, СправочникСсылка.Номенклатура) — это компактное значение, которое однозначно идентифицирует запись в базе данных. У ссылки доступны только предопределённые свойства: уникальный идентификатор, признак пустой ссылки и некоторые системные поля. Попытка прочитать произвольный реквизит через ссылку вызывает обращение к базе (неявный запрос), а в клиент-серверном режиме — серверный вызов.

Объект (например, СправочникОбъект.Номенклатура) получают методом ПолучитьОбъект() у ссылки. Объект загружает все реквизиты и табличные части в память, позволяет их менять и записывать методом Записать(). Работа с объектом тяжелее: это полное чтение данных, а при записи — срабатывание всех подписок и обработчиков.

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

Как определить тип значения через ТипЗнч

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

Если ТипЗнч(Значение) = Тип("СправочникСсылка.Номенклатура") Тогда

// Это ссылка на справочник «Номенклатура»

ИначеЕсли ТипЗнч(Значение) = Тип("СправочникОбъект.Номенклатура") Тогда

// Это объект справочника «Номенклатура»

КонецЕсли;

Когда нужно проверить принадлежность к целому классу типов (любая ссылка, любой документ), удобнее использовать описание типов или проверку через метаданные. Например, определить, что значение — ссылка на любой документ, можно так:

Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда

// Значение — ссылка на какой-либо документ

КонецЕсли;

Аналогичные коллекции есть у справочников, планов счетов, планов видов характеристик и других объектов метаданных: Справочники.ТипВсеСсылки(), ПланыВидовХарактеристик.ТипВсеСсылки(). Это надёжнее, чем перечисление конкретных типов вручную.

bsl
Если ТипЗнч(ЗначениеПроверки) = Тип("СправочникСсылка.Номенклатура") Тогда
    Сообщить("Это ссылка");
ИначеЕсли ТипЗнч(ЗначениеПроверки) = Тип("СправочникОбъект.Номенклатура") Тогда
    Сообщить("Это объект");
Иначе
    Сообщить("Другой тип данных");
КонецЕсли;

Как проверить ссылку на пустоту и заполненность

Пустая ссылка — это ссылка с нулевым уникальным идентификатором, не указывающая ни на одну запись. Проверяется она методом Пустая() или сравнением с пустым значением нужного типа:

Если СсылкаНаТовар.Пустая() Тогда

// Ссылка не заполнена

КонецЕсли;

// Альтернатива:

Если СсылкаНаТовар = Справочники.Номенклатура.ПустаяСсылка() Тогда

// То же самое

КонецЕсли;

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

Типичная ошибка — проверять ссылку на равенство Неопределено, когда реквизит просто не заполнен. Незаполненный реквизит ссылочного типа содержит пустую ссылку, а не Неопределено, поэтому проверка Если Реквизит = Неопределено не сработает. Используйте ЗначениеЗаполнено() или Пустая().

Типичные ошибки
01
Проверка ссылки на Неопределено вместо проверки на пустую ссылку — незаполненный реквизит содержит пустую ссылку, и условие не сработает.
02
Чтение реквизитов через ссылку в цикле — каждое обращение вызывает запрос к базе, что резко замедляет обработку.
03
Вызов ПолучитьОбъект() без проверки существования ссылки — для «битой» ссылки метод вернёт Неопределено, и следующая строка вызовет ошибку.
04
Сравнение ссылки и объекта оператором равенства — это разные типы, сравнение может дать неожиданный результат.

Как проверить, существует ли ссылка в базе данных

Ссылка может быть заполнена, но запись в базе уже удалена — такую ссылку называют «битой». При обращении к реквизитам через неё вы увидите строку вида «Объект не найден». Проверить существование записи можно несколькими способами.

Способ 1 — запрос. Самый универсальный и быстрый вариант, особенно при массовой проверке:

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 ИСТИНА

|ИЗ Справочник.Номенклатура

|ГДЕ Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ПроверяемаяСсылка);

СсылкаСуществует = Не Запрос.Выполнить().Пустой();

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

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

Как проверить объект перед записью

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

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

ОбъектТовара = СсылкаНаТовар.ПолучитьОбъект();

Если ОбъектТовара = Неопределено Тогда

ВызватьИсключение "Элемент не найден в базе";

КонецЕсли;

ОбъектТовара.Наименование = НовоеНаименование;

Если ОбъектТовара.ПроверитьЗаполнение() Тогда

ОбъектТовара.Записать();

Иначе

// Сообщения об ошибках уже выведены платформой

КонецЕсли;

В-третьих, учитывайте блокировки. Если тот же объект в этот момент редактирует другой пользователь, при записи возникнет конфликт блокировок. В интерактивной работе платформа сообщит об этом; в фоновых и регламентных заданиях ошибку нужно обрабатывать через попытку/исключение и, при необходимости, повторять операцию.

Как проверить тип объекта через метаданные

Иногда нужно не просто сравнить тип с конкретным значением, а узнать, к какому виду метаданных относится значение: справочник это, документ или что-то иное. Для этого служит функция Метаданные.НайтиПоТипу():

МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(Значение));

Если МетаданныеЗначения <> Неопределено Тогда

Если Метаданные.Справочники.Содержит(МетаданныеЗначения) Тогда

// Это справочник

ИначеЕсли Метаданные.Документы.Содержит(МетаданныеЗначения) Тогда

// Это документ

КонецЕсли;

КонецЕсли;

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

Учтите: НайтиПоТипу() возвращает Неопределено для примитивных типов (строка, число, дата), поэтому проверка на Неопределено обязательна перед обращением к свойствам результата.

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

Запрос к базе

Быстро и подходит для массовых проверок; требует написания текста запроса под конкретный тип или построения универсального запроса.

ПолучитьОбъект() и проверка на Неопределено

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

Готовая функция общего модуля (например, из БСП)

Оптимально, если конфигурация на библиотеке стандартных подсистем; недоступно в самописных конфигурациях без такой библиотеки.

Практический порядок проверки значения

Соберём всё в единый алгоритм, который подходит для большинства ситуаций, когда в процедуру приходит неизвестное значение и нужно безопасно с ним работать.

Порядок действий
  1. 1
    Проверьте значение через ЗначениеЗаполнено() — отсечь Неопределено, пустые ссылки и пустые примитивы.
  2. 2
    Определите тип через ТипЗнч() и сравните с ожидаемым типом ссылки или объекта.
  3. 3
    Если это ссылка — проверьте её существование запросом или функцией общего модуля.
  4. 4
    Если нужно менять данные — получите объект через ПолучитьОбъект() и убедитесь, что результат не Неопределено.
  5. 5
    Перед записью вызовите ПроверитьЗаполнение() и обработайте возможные ошибки блокировки через Попытка/Исключение.
  6. 6
    После записи проверьте результат: перечитайте данные или убедитесь в отсутствии сообщений об ошибках.

Такой порядок исключает три самые частые аварийные ситуации: обращение к пустой ссылке, чтение реквизитов «битой» ссылки и запись объекта с незаполненными обязательными полями. В отладчике контролировать тип значения помогает табло: достаточно вычислить выражение ТипЗнч(Переменная) и посмотреть результат.

Контрольные точки

Как проверить результат

Тип значения в отладчике
Норма

Показывает ожидаемый тип, например «СправочникСсылка.Номенклатура»

Тревожный признак

Тип «Неопределено» или «Строка» там, где ожидалась ссылка

Чтение реквизита через ссылку
Норма

Возвращается реальное значение реквизита

Тревожный признак

Строка вида «Объект не найден» или ошибка обращения

Результат ПолучитьОбъект()
Норма

Возвращён объект, доступны реквизиты

Тревожный признак

Возвращено Неопределено — записи в базе нет

Запись объекта
Норма

Записать() выполняется без исключений, ПроверитьЗаполнение() вернула Истина

Тревожный признак

Ошибка блокировки или сообщения о незаполненных полях

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

Чем отличается проверка «Пустая()» от «ЗначениеЗаполнено()»?

Метод Пустая() есть только у ссылок и проверяет, что ссылка нулевая. ЗначениеЗаполнено() — универсальная функция для любых типов: она проверяет пустые ссылки, пустые строки, нулевые числа, пустые даты и Неопределено. Для реквизитов неизвестного или смешанного типа используйте ЗначениеЗаполнено(), для гарантированно ссылочных значений оба варианта равнозначны.

Можно ли сравнивать ссылку и объект оператором «=»?

Технически сравнение выполнится, но ссылка и объект — разные типы, и результат может не совпасть с ожиданиями. Правильный подход: сравнивать ссылку объекта со ссылкой. У объекта ссылка доступна через свойство Ссылка: Если ОбъектТовара.Ссылка = ИскомаяСсылка Тогда.

Что такое «битая» ссылка и как её найти?

Это ссылка на удалённую или никогда не существовавшую запись. При чтении её реквизитов отображается «Объект не найден». Найти такие ссылки можно запросом с левым соединением к таблице объекта: если связанная запись NULL, ссылка битая. Также в типовых конфигурациях есть штатные средства поиска и удаления битых ссылок.

Как проверить тип значения, если оно может быть любым объектом конфигурации?

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

Нужно ли получать объект, чтобы прочитать реквизиты?

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

Почему ПолучитьОбъект() вернул Неопределено?

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

Итог

Что важно запомнить

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