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