Дерево значений под отладкой: от разворота строк до выгрузки в таблицу

· 9 мин

Содержание

Чтобы посмотреть дерево значений в отладчике 1С, поставьте точку останова (F9) на строке после заполнения дерева, дождитесь остановки, выделите имя переменной и нажмите Shift+F9 — откроется окно «Вычислить выражение». В нём разверните свойство Строки: каждая строка дерева содержит свои значения колонок и собственную коллекцию Строки с подчинёнными элементами. Для постоянного наблюдения перетащите переменную в табло (Ctrl+Alt+W).

Ручной разворот удобен, пока в дереве десяток строк и два-три уровня. Если строк сотни, а нужная запись лежит на пятом уровне, быстрее одной строкой кода превратить дерево в плоскую таблицу или в табличный документ с отступами. Все три приёма работают в конфигураторе платформы 8.3, отладка в 1С:EDT устроена похоже.

Из чего состоит дерево значений и как оно выглядит под отладкой

ДеревоЗначений — универсальная коллекция с иерархией. В отличие от таблицы значений, строки здесь вложены друг в друга. У объекта два главных свойства:

  • 📋 Колонки — описание колонок: имя, тип значения, заголовок;
  • 🌳 Строки — коллекция строк верхнего уровня.

Каждая строка (СтрокаДереваЗначений) хранит значения колонок и ещё два свойства:

  • 🔽 Строки — подчинённые строки этого узла;
  • 🔼 Родитель — ссылка на строку уровнем выше (у верхнего уровня — Неопределено).

Отсюда главная особенность просмотра. Отладчик показывает дерево не как иерархический список, а как вложенные свойства. Чтобы добраться до третьего уровня, нужно развернуть Строки → [0] → Строки → [2] → Строки и так далее. В окне это выглядит как матрёшка, и на больших данных легко потеряться.

Что хотите увидетьГде смотреть в отладчике
Сколько колонок и как они называютсяДерево.Колонки
Строки верхнего уровняДерево.Строки
Детей конкретного узлаДерево.Строки[0].Строки
Значение колонки у строкиДерево.Строки[0].Строки[1].Сумма
Уровень вложенности строкиТекСтрока.Уровень()

Индексы строк в выражениях считаются с нуля. Первая строка верхнего уровня — Дерево.Строки[0], а не [1].

Перед отладкой: где поставить точку останова

Дерево значений видно только там, где оно существует как переменная. Отсюда три правила.

  1. Останавливайтесь после заполнения. Точка на строке Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) сработает до присваивания, и вы увидите старое значение. Ставьте точку на следующую строку.
  2. Учитывайте контекст выполнения. Дерево, собранное в процедуре с директивой &НаСервере, живёт только на сервере. Чтобы остановиться внутри, отладка на сервере должна быть включена. В файловой базе серверный код выполняется в процессе клиента, и отдельной настройки обычно не требуется. В клиент-серверной базе сервер 1С нужно запустить с поддержкой отладки.
  3. Различайте дерево и реквизит формы. Если дерево лежит в реквизите формы, на клиенте отладчик покажет не ДеревоЗначений, а ДанныеФормыДерево.

Последний пункт чаще всего сбивает с толку. У ДанныеФормыДерево нет свойства Строки. Подчинённые элементы получают методом ПолучитьЭлементы(), а родителя — методом ПолучитьРодителя():

// На клиенте, реквизит формы типа ДеревоЗначений
Объект.Номенклатура.ПолучитьЭлементы()[0].ПолучитьЭлементы()[1].Количество

На сервере тот же реквизит можно превратить в обычное дерево через РеквизитФормыВЗначение("Номенклатура") и уже его разворачивать привычным способом.

Способ 1. Разворачиваем дерево в окне «Вычислить выражение» и в табло

Это базовый способ, ему не нужен дополнительный код.

Окно «Вычислить выражение»

  1. Дождитесь остановки на точке останова.
  2. Выделите в модуле имя переменной с деревом, например ДеревоОстатков.
  3. Нажмите Shift+F9 или выберите в меню Отладка → Вычислить выражение.
  4. В таблице результата раскройте узел переменной, затем Строки.
  5. Раскройте нужную строку: в ней вы увидите значения всех колонок и вложенную коллекцию Строки.
  6. Повторяйте, пока не дойдёте до нужного уровня.

В поле «Выражение» можно сразу писать путь до нужного узла: ДеревоОстатков.Строки[2].Строки[0]. Это быстрее, чем кликать по плюсикам, особенно если адрес строки вы уже знаете.

У окна есть команда показа значения в отдельном окне. Для коллекций она открывает удобный просмотр с колонками. Если в вашей версии платформы дерево открывается в таком окне без иерархии, переходите к способу 2: плоская таблица даст тот же обзор, но со всеми уровнями сразу.

Табло

Табло (Отладка → Табло или Ctrl+Alt+W) хранит выражения между остановками. Добавьте в него переменную с деревом и пару точечных выражений:

  • ДеревоОстатков.Строки.Количество() — сколько узлов верхнего уровня;
  • ТекСтрока.Уровень() — на какой глубине сейчас цикл;
  • ТекСтрока.Родитель — кто родитель текущего узла.

При пошаговом проходе (F10 — шаг через, F11 — шаг в процедуру) табло обновляется само. Так удобно отслеживать, как дерево заполняется в цикле.

Разворот очень большого дерева в окне отладчика может подвесить конфигуратор на десятки секунд. Если в дереве тысячи строк, не раскрывайте корень целиком — сразу пишите выражение до нужного узла или используйте способ 2.

Как анализировать свойства дерева значений выражениями

Окно «Вычислить выражение» умеет не только показывать переменные, но и вызывать методы коллекций. Это быстрый способ ответить на вопрос «есть ли нужная строка и где она».

ЗадачаВыражение
Число строк верхнего уровняДерево.Строки.Количество()
Найти первую строку по значению во всех уровняхДерево.Строки.Найти("Гвозди", "Номенклатура", Истина)
Найти все строки по условию во всех уровняхДерево.Строки.НайтиСтроки(Новый Структура("Склад", Склад), Истина)
Глубина найденной строкиНайденная.Уровень()
Цепочка родителейНайденная.Родитель.Родитель
Типы колонокДерево.Колонки.Сумма.ТипЗначения

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

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

💡 Частый вопрос под отладкой: «почему итог в группе не совпадает с суммой строк». Сравните значение колонки у группы с выражением Дерево.Строки[0].Строки.Итог("Сумма"). Метод Итог() считает только по переданной коллекции, без вложенных уровней, поэтому для проверки многоуровневой группы вызывайте его на каждом уровне.

Способ 2. Выгружаем дерево в плоскую таблицу значений

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

Добавьте функцию в общий отладочный модуль (серверный, с флагом «Вызов сервера» при необходимости) или в расширение, чтобы не трогать типовую конфигурацию :

// Превращает дерево значений в плоскую таблицу.
// ОтладкаУровень — глубина строки, ОтладкаПуть — адрес вида [0][2][1].
Функция ДеревоВТаблицу(Дерево) Экспорт

	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("ОтладкаУровень");
	Результат.Колонки.Добавить("ОтладкаПуть");
	Для Каждого Колонка Из Дерево.Колонки Цикл
		Результат.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения);
	КонецЦикла;

	ДобавитьВетку(Дерево.Строки, Результат, "");
	Возврат Результат;

КонецФункции

Процедура ДобавитьВетку(Строки, Результат, ПутьРодителя)

	Индекс = 0;
	Для Каждого СтрокаДерева Из Строки Цикл
		Путь = ПутьРодителя + "[" + Формат(Индекс, "ЧН=0; ЧГ=0") + "]";
		НоваяСтрока = Результат.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДерева);
		НоваяСтрока.ОтладкаУровень = СтрокаДерева.Уровень();
		НоваяСтрока.ОтладкаПуть = Путь;
		ДобавитьВетку(СтрокаДерева.Строки, Результат, Путь);
		Индекс = Индекс + 1;
	КонецЦикла;

КонецПроцедуры

Как пользоваться:

  1. Остановитесь в точке, где дерево уже заполнено.
  2. В окне «Вычислить выражение» введите ОтладкаСервер.ДеревоВТаблицу(ДеревоОстатков), где ОтладкаСервер — имя вашего модуля.
  3. Откройте результат в отдельном окне: перед вами вся иерархия, отсортированная по обходу дерева.
  4. Нашли подозрительную строку с путём [1][0][3] — значит, в исходном дереве это ДеревоОстатков.Строки[1].Строки[0].Строки[3].

Префикс Отладка у служебных колонок нужен, чтобы имена не совпали с колонками дерева. Колонка Уровень в отчётных деревьях встречается часто, и без префикса Колонки.Добавить() выдал бы ошибку о дублирующемся имени.

Новый общий модуль меняет конфигурацию. Пока сеанс отладки запущен, изменения не применятся: обновите конфигурацию базы данных и перезапустите отлаживаемый сеанс. В рабочей базе такие модули не добавляйте — делайте это в копии или в расширении.

Способ 3. Отладочный табличный документ с отступами

Табличный документ удобен, когда дерево нужно показать коллеге, сравнить два прогона или сохранить для разбора. Уровень вложенности передаётся отступом в первой колонке, поэтому иерархия читается глазами.

// Выводит дерево в табличный документ: шапка + строки с отступом по уровню.
Функция ДеревоВТабличныйДокумент(Дерево) Экспорт

	ТабДок = Новый ТабличныйДокумент;
	НомерКолонки = 1;
	Для Каждого Колонка Из Дерево.Колонки Цикл
		ТабДок.Область(1, НомерКолонки).Текст = Колонка.Имя;
		НомерКолонки = НомерКолонки + 1;
	КонецЦикла;

	НомерСтроки = 1;
	ВывестиВетку(ТабДок, Дерево.Строки, Дерево.Колонки, НомерСтроки);
	Возврат ТабДок;

КонецФункции

Процедура ВывестиВетку(ТабДок, Строки, Колонки, НомерСтроки)

	Для Каждого СтрокаДерева Из Строки Цикл
		НомерСтроки = НомерСтроки + 1;
		НомерКолонки = 1;
		Для Каждого Колонка Из Колонки Цикл
			ТабДок.Область(НомерСтроки, НомерКолонки).Текст = Строка(СтрокаДерева[Колонка.Имя]);
			НомерКолонки = НомерКолонки + 1;
		КонецЦикла;
		ТабДок.Область(НомерСтроки, 1).Отступ = СтрокаДерева.Уровень();
		ВывестиВетку(ТабДок, СтрокаДерева.Строки, Колонки, НомерСтроки);
	КонецЦикла;

КонецПроцедуры

НомерСтроки передаётся в рекурсию по ссылке, поэтому нумерация сквозная: после вывода ветки следующая строка верхнего уровня встаёт сразу под последним ребёнком.

Где посмотреть результат:

  • 🖥️ на клиенте — вызовите функцию с сервера, верните документ и покажите его: ТабДок.Показать("Дерево остатков");
  • 💾 в файл — на сервере выполните ТабДок.Записать("C:\Temp\derevo.mxl") и откройте файл в конфигураторе через Файл → Открыть;
  • 🔍 в отладчике — вычислите выражение с вызовом функции и откройте результат в отдельном окне.

Запись в файл на сервере сохраняет его на диск компьютера, где работает сервер 1С, а не на ваш. Для файловой базы это один и тот же компьютер, для клиент-серверной — нет.

Сравнение способов просмотра

СпособКогда подходитОграничения
Окно «Вычислить выражение» и таблоНебольшое дерево, нужен один-два узлаМедленно на больших деревьях, много ручного разворота
Выражения Найти() / НайтиСтроки()Известно, что искатьНужно знать имя колонки и значение
Плоская таблица значенийОбзор всего дерева, поиск аномалийНужен отладочный модуль в конфигурации или расширении
Табличный документСохранить, показать, сравнить два прогонаЗначения превращаются в строки, ссылки уже не раскрыть

Ошибки, которые мешают увидеть дерево

Диагностика: выберите симптом

Ещё две ловушки, которые не дают ошибок, но путают выводы:

  • 🔁 Изменение дерева во время просмотра. Выражение вида Дерево.Строки.Добавить() в окне вычисления реально добавит строку в отлаживаемом коде. Любой вызов метода с побочным эффектом меняет данные, и дальнейшее выполнение пойдёт уже с ними.
  • 🧮 Дерево из запроса без итогов. Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) строит иерархию только по полям из секции ИТОГИ ПО. Если её нет, дерево получится одноуровневым, и в отладчике вы не найдёте ожидаемых групп.

Частые вопросы

Можно ли в отладчике изменить значение в строке дерева?
Да. В окне «Вычислить выражение» выделите значение колонки и измените его. После продолжения выполнения код увидит уже новое значение.
Как скопировать дерево из отладчика в текст?
Вычислите ЗначениеВСтрокуВнутр(Дерево) и скопируйте результат. Строка неудобна для чтения, но её можно восстановить обратно через ЗначениеИзСтрокиВнутр() в тестовой обработке.
Почему в дереве из запроса пустые значения у групп?
В группировочных строках заполнены только поля группировки и итоговые ресурсы. Остальные колонки у групп остаются пустыми — это не ошибка.
Работает ли просмотр дерева значений в 1С:EDT?
Да. Дерево отображается в панели переменных, вложенные строки раскрываются так же, через свойство «Строки». Выражения с Найти() и вызовом отладочных функций работают и там.
Нужна ли отладочная функция в рабочей базе?
Нет. Держите её в расширении, которое подключаете только на время разбора, или в копии базы.