Как программно изменить тип вычисляемого поля в СКД и применить его к таблице значений?

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

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

В этой статье мы подробно разберем, почему платформа «1С:Предприятие» ведет себя подобным образом, проанализируем внутренние механизмы кэширования СКД и рассмотрим два надежных способа решения этой задачи.

Почему тип поля не меняется в итоговой таблице значений?

Выясним причину такого поведения платформы. Когда мы программно изменяем свойства вычисляемого поля непосредственно в схеме компоновки данных:

НужныйОтчет.СхемаКомпоновкиДанных.ВычисляемыеПоля[9].ТипЗначения = Новый ОписаниеТипов(...);

Эти изменения затрагивают только саму схему. Однако компоновщик настроек (КомпоновщикНастроекКомпоновкиДанных), который используется для генерации макета, жестко кэширует структуру полей при своей первоначальной инициализации. Он хранит структуру типов во внутреннем «Источнике доступных настроек».

Когда мы вызываем метод Выполнить() у объекта КомпоновщикМакетаКомпоновкиДанных, передавая туда схему и текущие настройки, система обращается к закэшированным типам данных. Изменения, внесенные в схему напрямую, игнорируются, и на выходе мы получаем тип по умолчанию — для строковых вычисляемых полей это строка неограниченной длины.

Кроме того, в отличие от языка запросов, в языке выражений СКД не существует функции ВЫРАЗИТЬ с возможностью ограничения длины строки (конструкция вида ВЫРАЗИТЬ(Поле КАК Строка(500)) вызовет синтаксическую ошибку). Единственный способ ограничить длину на уровне СКД — правильно настроить свойство ТипЗначения.


Решение 1. Переинициализация Компоновщика настроек через Временное хранилище

Рассмотрим самый правильный и «чистый» способ решения проблемы на уровне СКД. Чтобы компоновщик настроек увидел изменения в типах полей схемы, его необходимо принудительно обновить с использованием временного хранилища.

Разберем по шагам, как должен выглядеть этот процесс в коде:

  1. Вносим изменения в вычисляемое поле схемы компоновки данных.
  2. Помещаем модифицированную схему во временное хранилище.
  3. Создаем новый объект ИсточникДоступныхНастроекКомпоновкиДанных на основании адреса во временном хранилище.
  4. Инициализируем компоновщик настроек этим источником и восстанавливаем (загружаем) настройки.

Посмотрим на пример практической реализации данного метода:


// 1. Получаем схему компоновки данных отчета
СхемаКД = НужныйОтчет.СхемаКомпоновкиДанных;

// Безопасный поиск вычисляемого поля по имени вместо обращения по индексу
ИмяПоля = "МоеВычисляемоеПоле";
ВычисляемоеПоле = СхемаКД.ВычисляемыеПоля.Найти(ИмяПоля);

Если ВычисляемоеПоле <> Неопределено Тогда
    // Важно: в функцию БСП передаем число 500, а не строку "500"
    ВычисляемоеПоле.ТипЗначения = ОбщегоНазначения.ОписаниеТипаСтрока(500);
КонецЕсли;

// 2. Помещаем измененную схему во временное хранилище
АдресСхемыВоВременномХранилище = ПоместитьВоВременноеХранилище(СхемаКД, Новый УникальныйИдентификатор);

// 3. Создаем новый источник доступных настроек
НовыйИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемыВоВременномХранилище);

// 4. Переинициализируем компоновщик настроек отчета
НужныйОтчет.КомпоновщикНастроек.Инициализировать(НовыйИсточникНастроек);

// 5. Загружаем существующие настройки обратно, чтобы обновить их связь со схемой
ТекущиеНастройки = НужныйОтчет.КомпоновщикНастроек.Настройки;
НужныйОтчет.КомпоновщикНастроек.ЗагрузитьНастройки(ТекущиеНастройки);

Важное примечание по функциям БСП: в Сообщении 1 автор использует конструкцию ОбщегоНазначения.ОписаниеТипаСтрока("500"). В некоторых версиях Библиотеки стандартных подсистем строгая проверка типов внутри этой функции может проигнорировать строковый параметр и вернуть описание типа строки по умолчанию (без ограничения длины). Всегда передавайте числовое значение: ОбщегоНазначения.ОписаниеТипаСтрока(500).


Решение 2. Быстрая типизация колонок таблицы значений (Постобработка)

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

Вместо медленного перебора строк и копирования данных вручную, мы можем быстро типизировать нужную колонку с помощью методов СкопироватьКолонки() и ЗаполнитьЗначенияСвойств().

Проанализируем этот алгоритм на примере кода:


// Предположим, ТабОтчета — это таблица значений, полученная после вывода СКД,
// в которой колонка "Адрес" имеет тип "Строка" неограниченной длины.

// 1. Создаем копию структуры таблицы без самих данных
ТабСНовымиТипами = ТабОтчета.СкопироватьКолонки();

// 2. Находим индекс проблемной колонки
ИндексКолонки = ТабСНовымиТипами.Колонки.Индекс(ТабСНовымиТипами.Колонки.Адрес);

// 3. Удаляем старую колонку с неограниченной длиной
ТабСНовымиТипами.Колонки.Удалить(ИндексКолонки);

// 4. Создаем новое описание типа с ограничением длины
КвалификаторСтроки = Новый КвалификаторыСтроки(500);
НовыйТипПоля = Новый ОписаниеТипов("Строка",,,, КвалификаторСтроки);

// 5. Вставляем колонку на то же самое место, но уже с новым типом данных
ТабСНовымиТипами.Колонки.Вставить(ИндексКолонки, "Адрес", НовыйТипПоля, "Адрес доставки");

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

// В результате переменная ТабСНовымиТипами содержит готовую таблицу с ограниченной строкой

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

← На главную