К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как программно добавить строку в дерево значений 1С

Как программно добавить строку в дерево значений в 1С: метод Добавить(), работа с подчинёнными строками, заполнение колонок, типичные ошибки и примеры кода.

Дерево значений в 1С — иерархическая коллекция, где каждая строка может содержать подчинённые строки произвольной глубины. Программное добавление строк выполняется методом Добавить() коллекции строк, при этом важно понимать, у какого объекта этот метод вызывается: у самого дерева, у конкретной строки или у коллекции строк элемента формы. От этого зависит, на каком уровне иерархии появится новая запись.

Типичные задачи — заполнение дерева данными из запроса с группировками, построение иерархии справочника, формирование структуры для отображения в табличном поле формы. Во всех сценариях логика одинакова: сначала получается коллекция строк нужного уровня, затем в неё добавляется строка, после чего заполняются значения её колонок.

Материал ориентирован на разработчиков, работающих с управляемыми и обычными формами на платформе 1С:Предприятие 8.3. Примеры кода приведены на встроенном языке и применимы как на сервере, так и на клиенте, если не указано иное.

Структура дерева значений: что нужно понимать перед добавлением строк

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

Прежде чем добавлять строки, убедитесь, что колонки созданы. Если дерево объявлено как реквизит формы, колонки обычно добавляются в конфигураторе или программно при создании формы. Если дерево создаётся полностью в коде, колонки добавляются методом Колонки.Добавить("Имя", ОписаниеТипа) до начала заполнения строк.

Обращение к значению колонки у несуществующей колонки вызовет ошибку выполнения. Поэтому при динамическом построении дерева полезно проверять наличие колонки через Дерево.Колонки.Найти("ИмяКолонки") перед обращением к ней.

Добавление строки на корневой уровень дерева

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

Дерево = Новый ДеревоЗначений;

Дерево.Колонки.Добавить("Номенклатура");

Дерево.Колонки.Добавить("Количество");

НоваяСтрока = Дерево.Строки.Добавить();

НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000001");

НоваяСтрока.Количество = 10;

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

НоваяСтрока = Дерево.Строки.Добавить();

ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);

Если добавленная строка оказалась лишней, удалить её можно методом Удалить() у родительской коллекции: Дерево.Строки.Удалить(НоваяСтрока). Учтите, что удаление строки удаляет и все её подчинённые строки без возможности восстановления.

Добавление подчинённых строк: построение иерархии

Чтобы добавить строку на второй и более глубокие уровни, метод Добавить() вызывается у коллекции Строки конкретной родительской строки. Именно этот приём создаёт иерархию, а не плоский список.

СтрокаГруппа = Дерево.Строки.Добавить();

СтрокаГруппа.Номенклатура = "Группа товаров";

СтрокаЭлемент = СтрокаГруппа.Строки.Добавить();

СтрокаЭлемент.Номенклатура = "Товар внутри группы";

СтрокаЭлемент.Количество = 5;

Типичная ошибка новичков — добавлять все строки через Дерево.Строки.Добавить(), ожидая, что платформа сама построит иерархию по какому-либо признаку. Этого не происходит: уровень строки полностью определяется тем, у какой коллекции вызван метод Добавить().

Узнать родителя строки можно через свойство Родитель (у строк первого уровня оно равно Неопределено), а уровень вложенности — через метод Уровень(), где корневые строки имеют уровень 0. Это полезно при обходе дерева и при проверке корректности построенной структуры.

Порядок добавления строки в дерево
  1. 1
    Убедитесь, что у дерева созданы нужные колонки
  2. 2
    Определите уровень: корень (Дерево.Строки) или родительская строка (СтрокаРодителя.Строки)
  3. 3
    Вызовите Добавить() и сохраните возвращённую строку в переменную
  4. 4
    Заполните колонки напрямую или через ЗаполнитьЗначенияСвойств()
  5. 5
    Проверьте результат: количество строк, уровень вложенности, значения колонок

Заполнение дерева из запроса с иерархией

На практике дерево чаще всего заполняется результатом запроса с итогами по группировкам. Метод Выгрузить() результата запроса с параметром ТипОбходаРезультатаЗапроса.ПоГруппировкамСИерархией позволяет обойти выборку с сохранением иерархии и добавлять строки на соответствующие уровни.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Номенклатура

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ИТОГИ ПО

| Номенклатура ТОЛЬКО ИЕРАРХИЯ";

Результат = Запрос.Выполнить();

Дерево = Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

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

При ручном обходе выборки с иерархией используйте рекурсивную процедуру: она получает выборку текущего уровня и коллекцию строк, в которую добавляются элементы, затем вызывает сама себя для подчинённой выборки Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) и коллекции строк текущей строки дерева.

bsl
Процедура ДобавитьСтрокиРекурсивно(Выборка, КоллекцияСтрок)
	Пока Выборка.Следующий() Цикл
		НоваяСтрока = КоллекцияСтрок.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
		Подчиненные = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
		ДобавитьСтрокиРекурсивно(Подчиненные, НоваяСтрока.Строки);
	КонецЦикла;
КонецПроцедуры

Добавление строк в дерево на форме

Когда дерево значений является реквизитом формы и отображается в табличном поле, программное добавление строк выполняется тем же методом Добавить(), но с учётом контекста выполнения. На клиенте в управляемой форме доступны коллекции данных формы, поэтому код ЭлементыДерева = Дерево.ПолучитьЭлементы(); НоваяСтрока = ЭлементыДерева.Добавить(); является стандартным для реквизита типа ДанныеФормыДерево.

Обратите внимание на различие: для реквизита формы типа «ДеревоЗначений» используется свойство Строки, а для элемента формы «ТаблицаФормы», связанного с деревом, — метод ПолучитьЭлементы(). Смешение этих подходов — частая причина ошибок «Метод объекта не обнаружен».

После добавления строки на клиенте полезно установить текущую строку в табличном поле и при необходимости развернуть родительский узел: Элементы.Дерево.Развернуть(СтрокаРодителя.ПолучитьИдентификатор()). Без разворачивания новая подчинённая строка добавится, но пользователь её не увидит, что выглядит как «код не работает».

Проверка результата и обход дерева

После программного заполнения дерева результат проверяется обходом строк. Для плоской проверки первого уровня достаточно цикла Для Каждого Строка Из Дерево.Строки Цикл, а для полного обхода всех уровней — рекурсии или метода Найти() / НайтиСтроки() с параметром поиска по всем уровням.

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

Дополнительные контрольные точки: общее количество строк первого уровня (Дерево.Строки.Количество()), уровень конкретной строки (Строка.Уровень()), наличие подчинённых строк (Строка.Строки.Количество() > 0). Эти проверки помогают быстро локализовать ошибку, когда строки добавляются не на тот уровень.

Контрольные точки

Как проверить результат

Количество строк первого уровня
Норма

Совпадает с ожидаемым числом корневых элементов

Тревожный признак

Строк больше или меньше — проверьте цикл добавления

Уровень добавленной строки (Уровень())
Норма

0 для корня, 1 и выше для подчинённых

Тревожный признак

Все строки имеют уровень 0 — иерархия не построена

Значения колонок новой строки
Норма

Все колонки заполнены ожидаемыми данными

Тревожный признак

Пустые значения — ошибка в ЗаполнитьЗначенияСвойств или именах колонок

Отображение в табличном поле формы
Норма

Строка видна, узел родителя развёрнут

Тревожный признак

Строка есть в данных, но не видна — узел свёрнут

Типичные ошибки и ограничения

Наиболее распространённая ошибка — добавление строки не в ту коллекцию. Если вместо СтрокаРодителя.Строки.Добавить() вызвано Дерево.Строки.Добавить(), строка попадёт на корневой уровень, и иерархия разрушится. Визуально это проявляется как «плоский» список вместо дерева.

Вторая группа ошибок связана с типами данных. Если колонка дерева имеет ограниченный тип (например, только ссылка на конкретный справочник), попытка записать значение другого типа приведёт к ошибке преобразования. При заполнении из запроса следите, чтобы типы полей выборки соответствовали типам колонок дерева.

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

Ограничения: дерево значений существует только в памяти и не сохраняется в базе данных напрямую. Для длительного хранения его сериализуют через ЗначениеВСтрокуВнутр() или преобразуют в таблицу значений с потерей иерархии. Также при работе с большими деревьями (десятки тысяч строк) операции поиска и сортировки могут заметно замедляться — в таких случаях рассмотрите индексирование колонок или иной способ хранения.

Типичные ошибки
01
Вызов Добавить() у дерева вместо родительской строки — вся иерархия схлопывается в плоский список
02
Игнорирование возвращаемого значения Добавить() — колонки новой строки остаются пустыми
03
Путаница между Строки и ПолучитьЭлементы() в управляемой форме — ошибка вызова метода
04
Заполнение колонок до их создания в дереве — ошибка обращения к несуществующему свойству
05
Забытый Развернуть() после добавления подчинённой строки — пользователь не видит результат

FAQ

Как добавить строку в начало дерева, а не в конец?

Используйте метод Вставить() коллекции строк с индексом 0: Дерево.Строки.Вставить(0). Метод возвращает новую строку так же, как Добавить(), но размещает её в указанной позиции. Для вставки внутрь подчинённой коллекции вызовите Вставить() у Строки родительской строки.

Как скопировать строку со всеми подчинёнными строками?

Прямого метода копирования ветки нет. Добавьте новую строку через Добавить(), заполните её колонки через ЗаполнитьЗначенияСвойств(НоваяСтрока, ИсходнаяСтрока), а затем рекурсивно обойдите ИсходнаяСтрока.Строки, добавляя копии в НоваяСтрока.Строки.

Можно ли добавить строку в дерево на клиенте тонкого клиента?

Да, если дерево является реквизитом формы. В управляемой форме используйте Дерево.ПолучитьЭлементы().Добавить(). Если дерево создано как локальная переменная в серверной процедуре, на клиенте оно недоступно — перенесите заполнение на сервер или в реквизит формы.

Почему ЗаполнитьЗначенияСвойств не заполняет часть колонок?

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

Как найти строку в дереве и добавить к ней подчинённую?

Найдите строку методом Дерево.Строки.Найти(Значение, "ИмяКолонки", Истина) — третий параметр включает поиск по всем уровням. Если строка найдена (результат не равен Неопределено), добавьте подчинённую через НайденнаяСтрока.Строки.Добавить().

Чем дерево значений отличается от таблицы значений при добавлении строк?

Синтаксис Добавить() одинаков, но у таблицы значений все строки находятся на одном уровне и нет свойства Родитель или вложенных коллекций Строки. Если иерархия не нужна, таблица значений проще в обходе и быстрее при поиске по индексам.

Итог

Что важно запомнить

Строка добавляется методом Добавить() у коллекции строк нужного уровня: Дерево.Строки для корня, СтрокаРодителя.Строки для иерархии. Метод возвращает новую строку — сохраняйте её и заполняйте колонки сразу. В управляемой форме используйте ПолучитьЭлементы().Добавить() и не забывайте разворачивать узлы для отображения результата.