Разработка и Конфигурация · 9 мин
Как из запроса получить объект в 1С
Разбираем, как в 1С из запроса получить объект: выборка из результата запроса, получение ссылки и метода ПолучитьОбъект(), примеры кода, ошибки и проверка результата.
В языке запросов 1С нельзя напрямую получить объект с возможностью изменения: запрос всегда возвращает только данные для чтения — ссылки, значения полей, итоги. Чтобы получить объект, который можно изменить и записать, нужно пройти два шага: выполнить запрос, извлечь из результата ссылку, а затем вызвать у ссылки метод ПолучитьОбъект().
Путаница обычно возникает из-за смешения трёх разных сущностей: результата запроса, выборки и объекта. Результат запроса — это таблица данных. Выборка — курсор для последовательного обхода строк результата. Объект — программное представление элемента базы данных (справочника, документа), которое поддерживает изменение реквизитов и запись.
Ниже разобран полный путь от текста запроса до записи изменённого объекта: как правильно построить запрос, обойти выборку, получить объект, изменить его и не сломать данные при ошибках.
Как устроен путь от запроса к объекту
Механизм работы запросов в 1С устроен так: метод Запрос.Выполнить() обращается к базе данных и возвращает результат — неизменяемый набор строк. Из результата методом Выбрать() получают выборку, а методом Выгрузить() — таблицу значений. Ни выборка, ни таблица значений не являются объектами метаданных: это просто данные.
Если в тексте запроса выбрано поле Ссылка, то в выборке доступна ссылка на элемент справочника или документ. Ссылка — это лёгкий идентификатор записи. Уже у ссылки можно вызвать ПолучитьОбъект(), и платформа загрузит из базы полноценный объект со всеми реквизитами, табличными частями и методами записи.
Базовый пример: запрос, выборка, ПолучитьОбъект()
Типовой сценарий выглядит так: формируется запрос с параметром отбора, результат обходится в цикле, для каждой строки из ссылки создаётся объект, изменяются реквизиты, объект записывается. Пример для справочника номенклатуры:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Родитель = &Группа
| И НЕ Номенклатура.ПометкаУдаления";
Запрос.УстановитьПараметр("Группа", ГруппаТоваров);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбъектНоменклатуры = Выборка.Ссылка.ПолучитьОбъект();
ОбъектНоменклатуры.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;
ОбъектНоменклатуры.Записать();
КонецЦикла;
Обратите внимание на три момента. Во-первых, в запросе обязательно выбирается поле Ссылка — без него получить объект не удастся. Во-вторых, фильтр НЕ ПометкаУдаления отсекает помеченные элементы, которые обычно не нужно обрабатывать. В-третьих, каждый объект записывается отдельно внутри цикла.
Получение одного объекта без цикла
Когда запрос должен вернуть ровно одну запись, цикл не нужен. Используйте проверку Выборка.Следующий() один раз или метод Результат.Пустой(), чтобы убедиться, что данные найдены:
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокументОбъект.Комментарий = "Обработан программно";
ДокументОбъект.Записать();
Иначе
Сообщить("Документ не найден по заданным условиям");
КонецЕсли;
Частая ошибка — вызывать ПолучитьОбъект() без проверки, что выборка не пустая. Если Следующий() вернул Ложь, обращение к полям выборки даст неопределённые значения, а ПолучитьОбъект() от пустой ссылки вызовет исключение.
Получение объекта через таблицу значений
Альтернатива выборке — выгрузка результата в таблицу значений методом Выгрузить(). Это удобно, когда данные нужно сначала проанализировать, отсортировать нестандартно или передать в другую процедуру:
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
Для Каждого СтрокаТаблицы Из ТаблицаРезультата Цикл
ОбъектЭлемента = СтрокаТаблицы.Ссылка.ПолучитьОбъект();
ОбъектЭлемента.Наименование = СокрЛП(СтрокаТаблицы.Наименование);
ОбъектЭлемента.Записать();
КонецЦикла;
Разница принципиальна для производительности: выборка читает данные порционно по мере обхода, а Выгрузить() сразу помещает весь результат в память. Для больших результатов выборка предпочтительнее, для небольших — удобнее таблица.
Выборка или таблица значений
Экономит память на больших результатах, подходит для прямой обработки в цикле. Не позволяет вернуться к предыдущим строкам и сортировать после выполнения.
Позволяет сортировать, искать, сворачивать и передавать данные между процедурами. Загружает весь результат в память, что рискованно при сотнях тысяч строк.
Безопасная запись: транзакции и блокировки
Если в цикле обрабатывается много объектов и сбой посередине недопустим, оборачивайте обработку в транзакцию. Тогда при ошибке все изменения откатятся, а не останется половина обновлённых элементов:
НачатьТранзакцию();
Попытка
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбъектНоменклатуры = Выборка.Ссылка.ПолучитьОбъект();
ОбъектНоменклатуры.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка обработки: " + ОписаниеОшибки());
КонецПопытки;
Учтите обратную сторону: длинная транзакция удерживает блокировки на изменяемых записях и может мешать работе других пользователей. Для массовых обработок в многопользовательской базе иногда разумнее записывать порциями с фиксацией транзакции на каждой порции.
Типичные ошибки и как их избежать
Первая группа ошибок связана с самим запросом: забыто поле Ссылка в списке выбора, неверный параметр отбора, отсутствие проверки на пустой результат. Вторая группа — с объектом: попытка изменить ссылку вместо объекта, запись без установки обязательных реквизитов, игнорирование исключений при записи.
Ещё одна распространённая ситуация — обращение Выборка.Ссылка.Наименование вместо выбора поля в запросе. Каждое такое обращение через точку от ссылки вызывает отдельное обращение к базе. Если поле нужно только для чтения, выберите его прямо в тексте запроса — это в разы быстрее.
Как проверить, что всё сработало
После обработки убедитесь, что изменения реально применились. Минимальный набор проверок: количество обработанных строк совпадает с ожиданием, повторный запрос с тем же отбором показывает обновлённые значения, в журнале регистрации нет ошибок записи.
Как проверить результат
Совпадает с числом строк результата запроса
Часть строк пропущена или результат пустой при ожидаемых данных
Повторный запрос показывает новые значения
Значения старые — запись не выполнилась или была откачена
Нет ошибок записи и конфликтов блокировок
Ошибки блокировок, отказ в доступе или исключения при записи
FAQ
Можно ли получить объект напрямую из запроса, без ссылки?
Нет. Язык запросов 1С работает только с данными для чтения и никогда не возвращает объекты. Единственный путь — выбрать в запросе поле Ссылка, а затем вызвать у неё ПолучитьОбъект().
Чем отличается Ссылка от Объекта?
Ссылка — лёгкий идентификатор записи, позволяет только читать данные (через точку, с обращением к базе). Объект — полная копия записи в памяти с возможностью изменения реквизитов, табличных частей и записи. ПолучитьОбъект() преобразует ссылку в объект.
Почему ПолучитьОбъект() возвращает Неопределено?
Так бывает, если запись физически отсутствует в базе (битая ссылка) или у текущего пользователя нет прав на чтение объекта. Проверяйте результат перед использованием: Если Объект = Неопределено Тогда ... КонецЕсли.
Как получить объект, если запрос возвращает иерархическую выборку?
Используйте Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) и рекурсивно обходите вложенные выборки. На нужном уровне поле Ссылка доступно так же, как в линейной выборке, и ПолучитьОбъект() работает без изменений.
Что быстрее: обработка через выборку или через таблицу значений?
При простом последовательном обходе скорость сопоставима, но выборка потребляет меньше памяти. Таблица значений оправдана, когда нужны сортировка, поиск по строкам или повторные проходы по данным.
Нужно ли получать объект, если требуется только прочитать реквизиты?
Нет. Для чтения достаточно выбрать нужные поля в тексте запроса — это быстрее и не тратит память на загрузку объекта. ПолучитьОбъект() оправдан только когда данные нужно изменить и записать.
Что важно запомнить
Запрос в 1С возвращает только данные для чтения. Путь к объекту всегда один: Выполнить() → Выбрать() или Выгрузить() → поле Ссылка → ПолучитьОбъект() → изменение → Записать(). Проверяйте результат на пустоту, выбирайте нужные поля в запросе вместо обращений через точку, а массовые изменения выполняйте в транзакции после теста на копии базы.