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