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