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