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

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

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

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

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

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

Различие касается всех ссылочных типов данных: справочников, документов, планов счетов, планов видов характеристик и других. Для них существуют пары типов вида «СправочникСсылка.Номенклатура» и «СправочникОбъект.Номенклатура», «ДокументСсылка.РеализацияТоваровУслуг» и «ДокументОбъект.РеализацияТоваровУслуг».

Что такое ссылка и как она устроена

Ссылка — это значение, которое однозначно указывает на запись в базе данных. Внутри она содержит уникальный идентификатор (GUID) и указание на тип объекта метаданных. Сама по себе ссылка не хранит ни наименование элемента справочника, ни сумму документа — эти данные платформа подтягивает из базы по требованию, когда вы обращаетесь к реквизиту «через точку».

Ссылки можно сравнивать между собой, проверять на заполненность методом Пустая(), передавать в параметры запросов, хранить в реквизитах других объектов. Именно ссылки сохраняются в базе данных в полях ссылочного типа: когда в документе есть реквизит «Контрагент», физически в таблице хранится ссылка на элемент справочника контрагентов.

Важная особенность: получение ссылки не означает чтение всей записи. Когда вы перебираете результат запроса и работаете только со ссылками, платформа не загружает в память полные данные каждого элемента. Это делает операции со ссылками быстрыми и дешёвыми по ресурсам.

Что такое объект и чем он отличается по возможностям

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

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

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

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

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

bsl
ОбъектЭлемента = СсылкаНаЭлемент.ПолучитьОбъект();
Если ОбъектЭлемента = Неопределено Тогда
    Возврат; // ссылка битая, записи в базе нет
КонецЕсли;
ОбъектЭлемента.Наименование = "Новое наименование";
ОбъектЭлемента.Записать();

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

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

Как изменить элемент справочника программно
  1. 1
    Получите ссылку на элемент — из запроса, реквизита или метода НайтиПоКоду()
  2. 2
    Вызовите Ссылка.ПолучитьОбъект() и проверьте результат на Неопределено
  3. 3
    Измените нужные реквизиты объекта и при необходимости табличные части
  4. 4
    Вызовите метод Записать() и обработайте возможное исключение
  5. 5
    Проверьте результат: откройте элемент в режиме Предприятие или перечитайте реквизит запросом

Когда достаточно ссылки, а когда нужен объект

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

Тонкость в чтении реквизитов через ссылку: обращение вида Ссылка.Наименование работает, но каждое такое обращение в цикле — это отдельное неявное обращение к базе. Если нужно прочитать несколько реквизитов у множества элементов, правильнее использовать запрос с выборкой полей — он заберёт все данные одним обращением к СУБД.

Ссылка или объект: что выбрать

Ссылка

Чтение отдельных реквизитов, сравнение, параметры запросов, хранение в реквизитах. Не позволяет изменять данные и обращаться к табличным частям.

Запрос с выборкой полей

Массовое чтение реквизитов многих элементов. Самый быстрый вариант, но данные доступны только на чтение.

Объект

Любое изменение данных, запись, проведение, работа с табличными частями и обработчиками событий. Дороже по памяти и времени.

Типичные ошибки и ограничения

Самая частая ошибка — попытка записать значение в реквизит через ссылку: Ссылка.Наименование = "Текст". Платформа выдаёт ошибку «Поле объекта недоступно для записи», потому что ссылка по своей природе доступна только для чтения. Исправление всегда одно: получить объект и изменять его.

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

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

Ещё одно ограничение: у ссылки недоступны табличные части. Обращение вида Ссылка.Товары для документа не вернёт строки табличной части — для этого нужен либо объект, либо запрос к табличной части с отбором по ссылке.

Проверка результата и отладка

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

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

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

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

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

Отображается ожидаемый тип: СправочникСсылка или СправочникОбъект

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

Тип не совпадает с ожидаемым, значение Неопределено

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

Возвращён объект, реквизиты читаются

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

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

Данные после Записать()
Норма

Изменения видны при повторном чтении и в режиме Предприятие

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

Старые значения — запись не выполнялась или транзакция откачена

Частые вопросы о ссылках и объектах

Почему сравнение ссылки с объектом даёт ложь?

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

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

Да. Обращение через точку от ссылки (Ссылка.Наименование) читает реквизит напрямую из базы. Для массового чтения эффективнее запрос: он получает нужные поля множества записей одним обращением к СУБД.

Что вернёт ПолучитьОбъект() для удалённой записи?

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

Чем ПолучитьОбъект() отличается от выборки запросом?

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

Как узнать GUID ссылки?

Через метод УникальныйИдентификатор(): Ссылка.УникальныйИдентификатор(). Обратное восстановление ссылки по GUID выполняется методом менеджера ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID)).

Нужен ли объект, чтобы пометить документ на удаление?

Да. Пометка удаления — это изменение данных, поэтому потребуется получить объект и вызвать УстановитьПометкуУдаления(Истина). Через ссылку выполнить эту операцию нельзя.

Итог

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

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