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