Почему в 1С возникает «Объект не найден» вместо пустой ссылки и как проверить существование объекта?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При интеграции систем и загрузке данных из внешних источников (например, СУБД или сторонних сервисов) разработчики часто сталкиваются с ситуацией: при попытке получить ссылку по уникальному идентификатору (GUID) строковое представление возвращает «Объект не найден [<...>]». При этом вызов метода Ссылка.Пустая() возвращает Ложь, а строковая проверка через поиск подстроки выглядит ненадежно.

Разберем природу ссылочного типа в платформе 1С:Предприятие, выясним причины такого поведения платформы и рассмотрим правильные программные способы проверки существования объекта и его создания с предопределенным идентификатором.

Природа ссылки в платформе 1С: разница между пустой и «битой» ссылкой

Проанализируем структуру ссылки в оперативной памяти платформы. Ссылка на объект метаданных состоит из двух основных компонентов: типа метаданных (например, СправочникСсылка.Номенклатура) и 16-байтового уникального идентификатора (GUID).

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

  1. Пустая ссылка — это специальный предопределенный идентификатор, заполненный нулями (00000000-0000-0000-0000-000000000000). Только для такой ссылки метод Ссылка.Пустая() возвращает значение Истина. Пустая ссылка возвращается методом Справочники.ИмяСправочника.ПустаяСсылка().
  2. Ненайденная («битая») ссылка — это ссылка, содержащая конкретный, ненулевой GUID. Метод МенеджерСправочника.ПолучитьСсылку(УникальныйИдентификатор) не выполняет обращение к таблицам базы данных в СУБД, а просто конструирует ссылочное значение в памяти. Если в информационной базе нет физической строки с таким идентификатором, платформа при формировании представления сообщает: «Объект не найден». Технически такая ссылка не является пустой, поэтому метод Пустая() возвращает Ложь.

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

Почему не следует использовать ЗначениеИзСтрокиВнутр для обмена данными

Выясним, почему метод ЗначениеИзСтрокиВнутр непригоден для интеграции между разными базами и внешними системами. Данный метод преобразует внутреннее системное представление платформы, содержащее внутренние шестнадцатеричные идентификаторы типов конфигурации. Эти идентификаторы уникальны внутри конкретной информационной базы и не совпадают с другими базами, даже если конфигурации идентичны.

Кроме того, при получении сырых идентификаторов из SQL-таблиц напрямую следует учитывать порядок байтов (endianness). Платформа 1С при записи поля _IDRRef типа binary(16) переставляет байты в сравнении со стандартным строковым форматом GUID. Для штатной работы всегда используйте конструктор Новый УникальныйИдентификатор(СтрокаGUID), передавая строку формата XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (36 символов с дефисами).

Способ 1. Проверка существования записи через быстрый запрос

Разберем наиболее производительный и безопасный способ проверки наличия объекта в базе данных. Выполнение точечного запроса не считывает табличные части объекта и не накладывает лишних блокировок в транзакции.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	1 КАК Поле1
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Ссылка = &Ссылка";

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

Если РезультатЗапроса.Пустой() Тогда
    // Записи с таким GUID в базе данных нет, ссылка "битая"
    ОбъектСуществует = Ложь;
Иначе
    // Объект реально записан в информационной базе
    ОбъектСуществует = Истина;
КонецЕсли;

Способ 2. Использование функций Библиотеки Стандартных Подсистем (БСП)

Если в конфигурации внедрена БСП, не требуется писать запрос вручную. Разберем стандартные функции общего назначения, которые выполняют оптимизированную проверку:

  1. ОбщегоНазначенияКлиентСервер.ЭтоСсылка(Значение) — проверяет, принадлежит ли переданная переменная к ссылочному типу данных 1С.
  2. ОбщегоНазначения.СсылкаСуществует(Ссылка) — выполняет запрос к таблице базы данных и возвращает Истина, если объект существует, и Ложь, если ссылка не найдена.

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


Если НЕ ОбщегоНазначения.СсылкаСуществует(СсылкаДляПроверки) Тогда
    // Объект не найден в базе данных, переходим к его созданию
КонецЕсли;

Способ 3. Проверка через метод ПолучитьОбъект()

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

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


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

Если Объект = Неопределено Тогда
    // Объект не существует в базе
Иначе
    // Объект прочитан из базы, доступен для чтения и изменения
КонецЕсли;

Важно: этот способ не рекомендуется использовать при пакетной обработке больших массивов данных, так как считывание всех реквизитов и табличных частей создает повышенную нагрузку на сервер СУБД по сравнению с легким запросом ВЫБРАТЬ ПЕРВЫЕ 1.

Правильный алгоритм создания объекта с предопределенным GUID

Разберем по шагам, как корректно принять строковый GUID из сторонней системы, проверить наличие элемента и создать новый объект с сохранением исходного идентификатора:

  1. Приводим строку внешнего идентификатора к стандартному 36-символьному виду и создаем объект УникальныйИдентификатор.
  2. Получаем ссылку через менеджер соответствующего справочника или документа.
  3. Проверяем существование записи с помощью запроса или функции ОбщегоНазначения.СсылкаСуществует.
  4. Если объект не найден, создаем новый элемент методом СоздатьЭлемент() и связываем его с полученной ранее ссылкой через метод УстановитьСсылкуНового().
  5. Заполняем реквизиты и записываем объект.

Рассмотрим комплексный пример реализации:


СтрокаGUID = "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d";
Идентификатор = Новый УникальныйИдентификатор(СтрокаGUID);

// Конструируем ссылку в оперативной памяти
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(Идентификатор);

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

Ограничение платформы: метод УстановитьСсылкуНового() работает исключительно для новых объектов (пока свойство ЭтоНовый() возвращает Истина). После выполнения метода Записать() изменить системный GUID объекта штатным кодом невозможно.

← На главную