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