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