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