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