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