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

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

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

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

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

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

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

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

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

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

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

СсылкаНаЭлемент = Справочники.Номенклатура.НайтиПоКоду("000000123");

Если Не СсылкаНаЭлемент.Пустая() Тогда

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

Если ОбъектНоменклатуры <> Неопределено Тогда

ОбъектНоменклатуры.Наименование = "Новое наименование";

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

КонецЕсли;

КонецЕсли;

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

Проверка существования записи до и после получения объекта

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

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

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

Когда объект не нужен: чтение через ссылку и запрос

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

Сравните подходы, прежде чем писать код обхода большого списка:

ЗадачаПодходОсобенности
Прочитать 1–2 реквизита одной записиОбращение через ссылку: Ссылка.РеквизитБыстро, без объекта; каждое обращение — отдельный запрос
Прочитать реквизиты многих записейЗапрос с условием Ссылка В (&СписокСсылок)Один запрос на всю выборку, оптимально для циклов
Изменить данные записиСсылка.ПолучитьОбъект() + Записать()Единственный корректный способ модификации
Создать новую записьСправочники.Имя.СоздатьЭлемент()ПолучитьОбъект() тут не нужен — ссылки ещё нет
В циклах никогда не вызывайте ПолучитьОбъект() для каждой строки, если нужно только прочитать данные: на тысяче записей это даст тысячу обращений к базе. Вынесите чтение в один запрос до цикла, а ПолучитьОбъект() оставьте только для тех записей, которые реально изменяются.
ПЗ
Практическое замечание

Получение объекта в разных контекстах: сервер, клиент, обмен

Метод ПолучитьОбъект() доступен только на сервере и в толстом клиенте. В тонком и веб-клиенте он недоступен: попытка вызвать его в клиентском контексте приведёт к ошибке компиляции или выполнения. Поэтому в управляемых формах вся работа с объектами выносится в серверные процедуры с директивой &НаСервере или &НаСервереБезКонтекста. Из формы удобно использовать РеквизитФормыВЗначение("Объект") — этот метод возвращает объект данных текущей формы для модификации.

В планах обмена и при работе с COM-соединением логика та же: получили ссылку (или нашли её по уникальному идентификатору через ПолучитьСсылку(Новый УникальныйИдентификатор(...))), затем вызвали ПолучитьОбъект(). Если запись ещё не создана в этой базе, метод вернёт Неопределено — это штатный сигнал, что элемент нужно создать, а не ошибка.

Работа с уникальным идентификатором и битыми ссылками

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

Для диагностики «битых» ссылок в запросах используют проверку вида ГДЕ Таблица.Ссылка.Наименование ЕСТЬ NULL при левом соединении или функцию ЕСТЬNULL. Если ПолучитьОбъект() по такой ссылке вернул Неопределено, корректные действия — удалить или перезаполнить ссылку в том месте, где она хранится, а не пытаться записывать несуществующий объект.

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

Запись изменений и безопасность модификации

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

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

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

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

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

Переменная содержит объект нужного типа, реквизиты читаются

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

Значение равно Неопределено — запись отсутствует

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

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

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

Исключение: нарушение прав, блокировка или ошибка обработчика

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

Чтение идёт одним запросом, объекты создаются только для изменяемых записей

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

ПолучитьОбъект() вызывается в цикле для каждой строки

FAQ

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

Метод возвращает значение Неопределено. Это происходит, когда ссылка существует как идентификатор, но сама запись удалена или никогда не создавалась в этой базе. Перед обращением к реквизитам результата всегда проверяйте его сравнением с Неопределено.

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

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

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

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

Как получить объект, если известен только GUID в виде строки?

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

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

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

Итог

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

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