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

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

1С: как по ссылке получить объект

Как в 1С получить объект из ссылки: метод ПолучитьОбъект(), примеры кода на встроенном языке, проверка на пустую ссылку, типичные ошибки и FAQ.

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

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

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

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

Ссылка занимает минимум памяти и содержит, по сути, только уникальный идентификатор записи и тип. Когда вы пишете Ссылка.Номер или Ссылка.Контрагент, платформа неявно выполняет обращение к базе и возвращает значение реквизита. Это удобно для чтения одного-двух полей, но каждое такое обращение — потенциальный запрос к СУБД.

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

Базовый синтаксис ПолучитьОбъект()

Метод вызывается у переменной, содержащей ссылку, и возвращает объект соответствующего типа:

ДокументОбъект = ДокументСсылка.ПолучитьОбъект();

ДокументОбъект.Комментарий = "Скорректировано обработкой";

ДокументОбъект.Записать();

Тот же приём работает для справочников, планов видов характеристик, планов счетов, задач и других ссылочных типов. Если документ нужно перепровести, в Записать() передаётся режим проведения:

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

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

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

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

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

Если Ссылка.Пустая() Тогда

Возврат;

КонецЕсли;

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

Если Объект = Неопределено Тогда

// Запись удалена из базы, ссылка "битая"

Возврат;

КонецЕсли;

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

Когда объект получать не нужно

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

Для изменения одного реквизита без отработки событий ПередЗаписью и ПриЗаписи иногда применяют установку значений через запрос с конструкцией изменения — но в типовом коде такой приём используется редко, поскольку обходит бизнес-логику. Стандартный путь модификации — всегда через объект.

Сравнение вариантов

Обращение через ссылку (Ссылка.Реквизит)

Подходит для чтения 1–2 реквизитов. Не позволяет изменять данные; каждое обращение — потенциальный запрос к базе.

Запрос к данным

Оптимален для чтения многих записей и отборов. Только чтение, без событий объекта.

Ссылка.ПолучитьОбъект()

Единственный способ изменить и записать данные. Дорогая операция: читает запись целиком, включая табличные части.

Работа с объектом: изменение и запись

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

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

СпрОбъект.НаименованиеПолное = "ООО «Пример» (обновлено)";

Для Каждого СтрокаКонтакта Из СпрОбъект.КонтактнаяИнформация Цикл

// обработка строк табличной части

КонецЦикла;

СпрОбъект.Записать();

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

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

Особые случаи и ограничения

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

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

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

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

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

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

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

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

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

Возвращён объект нужного типа, реквизиты заполнены данными из базы

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

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

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

Метод завершился без исключения, изменения видны при повторном чтении

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

Исключение о блокировке, правах или проверке заполнения

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

Объект получается только для записей, которые реально изменяются

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

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

Частые вопросы

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

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

Можно ли изменить данные через ссылку без ПолучитьОбъект()?

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

Почему ПолучитьОбъект() не работает в модуле формы на клиенте?

Потому что метод доступен только на сервере. Вынесите получение и запись объекта в серверную процедуру общего модуля или в серверный контекст формы и вызывайте её с клиента.

Что быстрее: Ссылка.Реквизит или ПолучитьОбъект().Реквизит?

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

Как получить объект по строковому представлению уникального идентификатора?

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

Нужно ли освобождать объект после записи?

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

Итог

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

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