Как программно создать типизированные колонки таблицы значений на основе типов из структуры

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При разработке на платформе 1С:Предприятие 8.3 часто возникает задача преобразования массива структур в таблицу значений. Это необходимо для последующей сортировки, группировки или, что наиболее важно, для использования таблицы в качестве источника данных для ПостроителяЗапроса или СхемыКомпоновкиДанных. Однако простое создание колонок без указания типов приводит к тому, что система не может корректно наложить отборы или выполнить сравнение значений. В этой статье мы подробно разберем, как правильно типизировать колонки, чтобы они соответствовали типам данных в структурах, включая ссылочные типы и перечисления.

Почему важна явная типизация колонок?

Рассмотрим ситуацию: вы создаете таблицу значений и наполняете её данными. Если при добавлении колонки методом Колонки.Добавить() не указать второй параметр (ОписаниеТипов), 1С создаст колонку с типом Произвольный. Для обычного отображения в списке этого может быть достаточно, но при попытке использовать такую таблицу в ПостроителеЗапроса вы столкнетесь с ошибкой. Построитель запроса транслирует таблицу значений во временную таблицу СУБД (SQL), а SQL требует четкого определения типов данных и их длин. Если тип не определен, система передает данные как неопределенный тип, и фильтрация становится невозможной.

Разбор типичной ошибки: использование строкового представления типа

Часто начинающие разработчики пытаются определить тип, используя функцию Строка(ТипЗнч(Значение)). Проанализируем, почему этот путь тупиковый. При вызове ТипЗнч() для перечисления или справочника система возвращает объект типа Тип. Если превратить его в строку, вы получите представление вида "Учет начислений в среднем заработке (общий)". Попытка передать эту строку в конструктор ОписаниеТипов завершится неудачей, так как конструктор ожидает либо массив типов, либо строку с системным именем (например, "СправочникСсылка.Номенклатура"), но не пользовательское представление.

Правильный способ: Использование массива типов

Самый надежный и универсальный способ — это использование конструктора ОписаниеТипов, в который передается массив, содержащий реальные типы 1С. Выясним, как реализовать это в коде. Разберем по шагам алгоритм создания таблицы из массива структур.

Для начала рассмотрим базовую функцию, которая берет типы из первого элемента массива структур:


Функция МассивВТаблицуЗначений(МассивСтруктур)
    Таблица = Новый ТаблицаЗначений;
    
    Если МассивСтруктур.Количество() = 0 Тогда
        Возврат Таблица;
    КонецЕсли;
    
    // Берем первую структуру для определения состава колонок
    ПерваяСтруктура = МассивСтруктур[0];
    
    Для Каждого Элемент Из ПерваяСтруктура Цикл
        // Создаем массив для хранения типов текущей колонки
        МассивТипов = Новый Массив;
        МассивТипов.Добавить(ТипЗнч(Элемент.Значение));
        
        // Формируем ОписаниеТипов на основе массива типов
        НовоеОписаниеТипов = Новый ОписаниеТипов(МассивТипов);
        
        // Добавляем типизированную колонку
        Таблица.Колонки.Добавить(Элемент.Ключ, НовоеОписаниеТипов);
    КонецЦикла;
    
    // Заполняем таблицу данными
    Для Каждого ТекущаяСтруктура Из МассивСтруктур Цикл
        НоваяСтрока = Таблица.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекущаяСтруктура);
    КонецЦикла;
    
    Возврат Таблица;
КонецФункции

В этом примере мы создаем МассивТипов прямо внутри цикла обхода ключей структуры. Метод ТипЗнч(Элемент.Значение) возвращает объект типа Тип, который корректно воспринимается платформой, будь то примитивный тип (Число, Строка) или ссылочный тип (ПеречислениеСсылка, ДокументСсылка).

Проблема "пустого первого элемента" и ее решение

Проанализируем важный нюанс: что произойдет, если в первом элементе массива значение какого-то ключа будет равно Неопределено или NULL? В этом случае колонка получит тип Неопределено, и при заполнении последующих строк данными (например, ссылками на справочники) произойдет потеря данных или ошибка типизации. Чтобы сделать функцию по-настоящему универсальной, рекомендуется собрать все возможные типы для каждого ключа, обойдя весь массив структур.

Рассмотрим улучшенный алгоритм:


Функция МассивВТаблицуЗначенийУниверсально(МассивСтруктур)
    Таблица = Новый ТаблицаЗначений;
    
    Если МассивСтруктур.Количество() = 0 Тогда
        Возврат Таблица;
    КонецЕсли;

    // Сначала соберем все ключи (имена колонок)
    СоответствиеКолонокИТипов = Новый Соответствие; // Ключ - имя, Значение - Массив типов
    
    Для Каждого Структура Из МассивСтруктур Цикл
        Для Каждого Элемент Из Структура Цикл
            ТекущийТип = ТипЗнч(Элемент.Значение);
            Если ТекущийТип = Тип("Неопределено") Или ТекущийТип = Тип("NULL") Тогда
                Продолжить;
            КонецЕсли;
            
            СписокТипов = СоответствиеКолонокИТипов.Получить(Элемент.Ключ);
            Если СписокТипов = Неопределено Тогда
                СписокТипов = Новый Массив;
                СоответствиеКолонокИТипов.Вставить(Элемент.Ключ, СписокТипов);
            КонецЕсли;
            
            // Добавляем только уникальные типы
            Если СписокТипов.Найти(ТекущийТип) = Неопределено Тогда
                СписокТипов.Добавить(ТекущийТип);
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

    // Создаем колонки на основе собранных типов
    Для Каждого КлючИЗначение Из СоответствиеКолонокИТипов Цикл
        ОписаниеТиповКолонки = Новый ОписаниеТипов(КлючИЗначение.Значение);
        Таблица.Колонки.Добавить(КлючИЗначение.Ключ, ОписаниеТиповКолонки);
    КонецЦикла;

    // Заполнение данными
    Для Каждого Структура Из МассивСтруктур Цикл
        ЗаполнитьЗначенияСвойств(Таблица.Добавить(), Структура);
    КонецЦикла;

    Возврат Таблица;
КонецФункции

Использование механизмов БСП (Библиотека стандартных подсистем)

Если вы работаете в конфигурации, где внедрена БСП (например, ЗУП 3.1, ERP или Бухгалтерия 3.0), вам не обязательно писать этот код вручную. Разработчики 1С уже реализовали готовую функцию в общем модуле ОбщегоНазначения. Посмотрим на пример её вызова:


// МассивСтруктур - ваш исходный массив
ТаблицаРезультат = ОбщегоНазначения.ТаблицаЗначенийИзМассиваСтруктур(МассивСтруктур);

Эта функция внутри себя выполняет все необходимые проверки, корректно обрабатывает пустые значения и типизирует колонки. Использование стандартных функций повышает надежность вашего кода и упрощает его поддержку при обновлении платформы.

Особенности работы с примитивными типами

Посмотрим на важный технический момент: при создании ОписаниеТипов для чисел и строк через массив типов, система использует параметры по умолчанию. Для строк это будет длина 0 (переменная длина), а для чисел — стандартная точность. Если вам требуется строго задать, например, Строка(20) или Число(15, 2), использование только массива типов в конструкторе будет недостаточно. В таких случаях нужно использовать расширенный конструктор:


// Пример создания описания типов для числа с конкретной точностью
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2);
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
ОписаниеТиповЧисло = Новый ОписаниеТипов(МассивТипов, , , КвалификаторыЧисла);
Таблица.Колонки.Добавить("Сумма", ОписаниеТиповЧисло);

Как проверить результат типизации

Чтобы убедиться, что ваша таблица значений создана правильно, вы можете использовать следующий метод в отладчике или программно:

  1. Проверьте свойство Таблица.Колонки.ИмяКолонки.ТипЗначения. Оно должно содержать объект ОписаниеТипов.
  2. Вызовите метод ТипЗначения.Типы() — он вернет массив всех типов, которые разрешены в этой колонке.
  3. Если вы используете ПостроительЗапроса, попробуйте добавить колонку в ВыбранныеПоля и установить ДоступныеПоля. Если типы заданы верно, отбор в пользовательском интерфейсе будет предлагать выбор из справочника или перечисления, а не просто ввод текста.

Подведем итог: для создания универсального и надежного решения по преобразованию структур в таблицу значений, всегда используйте массив типов при инициализации ОписаниеТипов. Это гарантирует корректную работу с любыми объектами метаданных и обеспечит стабильную работу сложных механизмов платформы, таких как запросы и компоновка данных.

← На главную