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

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

Как получить объект из ссылки в 1С: практическое руководство

Как получить объект из ссылки в 1С через метод ПолучитьОбъект, когда он нужен, чем опасен и какие есть альтернативы: запросы, ДанныеФормыВЗначение, выборки.

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

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

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

Чем ссылка отличается от объекта и когда нужен каждый из них

Ссылка занимает минимум памяти и содержит по сути только уникальный идентификатор и тип. При обращении к реквизиту ссылки «через точку» (СсылкаНаКонтрагента.ИНН) платформа неявно выполняет запрос к базе и возвращает значение. Это удобно для разового чтения, но при обращении в цикле к нескольким реквизитам каждое обращение порождает отдельное обращение к СУБД.

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

Базовый синтаксис: ПолучитьОбъект для разных типов

Метод ПолучитьОбъект() доступен у ссылок всех ссылочных типов: справочников, документов, планов видов характеристик, планов счетов, задач, бизнес-процессов и других. Синтаксис одинаков:

КонтрагентОбъект = СсылкаНаКонтрагента.ПолучитьОбъект();

КонтрагентОбъект.Комментарий = "Проверен";

КонтрагентОбъект.Записать();

Для документов аналогично, с учётом режима записи:

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

ДокОбъект.Дата = ТекущаяДатаСеанса();

ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

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

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

Проверка ссылки перед получением объекта

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

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

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

Когда ПолучитьОбъект не нужен: альтернативы

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

Для массовой обработки (например, пересчёта поля у тысячи элементов) получение объекта каждого элемента — единственный способ записи, но читать данные для отбора следует запросом: сначала выбираются ссылки, затем в цикле получаются объекты только у нужных записей. Для изменения единственного простого реквизита иногда применяют УстановитьЗначение-подобные механизмы через объекты, но прямой записи «по ссылке» без объекта платформа не предоставляет.

В управляемых формах вместо объекта работают с данными формы: РеквизитФормыВЗначение("Объект") возвращает объект, а ЗначениеВРеквизитФормы помещает его обратно. Это корректный путь при интерактивном редактировании, а не прямой вызов ПолучитьОбъект() у ссылки формы.

Способы работы с данными по ссылке

Обращение через точку

Подходит для разового чтения одного-двух реквизитов. Не подходит для циклов — каждое обращение бьёт в СУБД

Запрос

Оптимален для чтения множества записей и полей. Не позволяет изменять данные

ПолучитьОбъект

Обязателен для изменения и записи. Дорог при массовом чтении — загружает весь объект целиком

Производительность и блокировки

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

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

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

Типичные ошибки и их последствия

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

Отдельная группа ошибок связана с обменом данными: при записи объекта срабатывают подписки на события и регистрация изменений для планов обмена. Если обработка служебная и не должна порождать регистрацию, используют Объект.ОбменДанными.Загрузка = Истина перед записью — но это отключает и проверки заполнения, поэтому применять приём нужно осознанно.

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

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

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

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

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

Возвращён объект нужного типа

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

Неопределено — ссылка пустая или запись удалена

После Записать()
Норма

Исключения нет, реквизиты в базе изменились

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

Ошибка блокировки или проверки заполнения

Документ после проведения
Норма

Ссылка.Проведен = Истина, движения присутствуют

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

Проведен = Ложь — запись выполнена без проведения

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

FAQ

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

Метод вернёт значение Неопределено, а не вызовет ошибку. Поэтому перед работой с результатом обязательна проверка: Если Объект = Неопределено Тогда Возврат; КонецЕсли.

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

Нет. Запись в базу выполняется только через объект: получить объект, изменить, вызвать Записать(). Для чтения объекта можно избежать — через запрос или обращение к реквизиту ссылки через точку.

Почему обращение Ссылка.Реквизит в цикле работает медленно?

Каждое обращение через точку к реквизиту ссылки порождает отдельный запрос к базе данных. В цикле по сотням записей это сотни запросов. Решение — один запрос, выбирающий все нужные поля сразу.

Как проверить, что ссылка не «битая»?

Выполните запрос к таблице объекта с условием Ссылка = &Ссылка и проверьте, что выборка не пустая. Альтернатива — получить объект и сравнить результат с Неопределено. Строковое представление «Объект не найден» тоже указывает на битую ссылку.

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

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

Нужно ли записывать объект после ПолучитьОбъект(), если ничего не менял?

Нет. Если изменений не было, вызов Записать() бессмысленен и вреден: он создаст лишнюю транзакцию, блокировку и сработавшие подписки на события. Записывайте только реально изменённые объекты.

Итог

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

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