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