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