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