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