Профессия — 1С » Материализованный путь в примерах

Профессия — 1С

Рукопашный бой Карташ

Категории

Материализованный путь в примерах

рубрики: Иерархические структуры | Дата: 18 Август, 2019
Скачать обработку с примерами из статьи: professia1c_MatherializedPath.epf
Платформа: 8.3; Тип формы: управляемая.

Введение

В прошлой статье были рассмотрены способы хранения иерархических структур в таблицах базы данных.




Сегодня хочется остановиться на одном из этих методов и рассмотреть его на примере. И этот метод — Matherialized Path (материализованный путь). Напомню вкратце, что суть этого метода в хранении полного пути в иерархии для каждого элемента.

Теория

Во многих статьях в интернете предлагается хранить путь в виде строки с разделителями. Например, верхний уровень — 1, подчиненные ему 1.1, 1.2 и т.д. Но такой способ не совсем удобен, т.к. при манипуляциях с деревом приходится парсить строку содержащую путь. Поэтому мы поступим немного по другому. Полный путь мы будем хранить в виде целого числа.Количество разрядов сделаем равным 6. И на каждый уровень в иерархии выделим по 2 знака. А для представления числа в форме в качестве разделителя разрядов будем использовать точку. Это легко реализовать используя оператор Формат()


Формат(100000, "ЧДЦ=0; ЧРГ=.; ЧГ=2,0") = "10.00.00"

Таким образом коды в нашей иерархической структуре будут выглядеть следующим образом


100000
  100100
  100200
    100201
110000
  110100
    110101
    110102
  110200
и т.д.

И по сути нам достаточно отсортировать записи в таблице по возрастанию кода, чтобы расположить строки в том порядке как они должны распологаться в дереве.




Таким образом при построении дерева отпадает необходимость в рекурсии, которая является достаточно затратной операцией с точки зрения производительности.

Конечно такой подход имеет и ряд недостатков. Мы искусственно ограничиваем количество уровней в иерархии и количество элементов на каждом уровне иерархии.

Пишем код

А теперь воплотим мысли из предыдущего раздела на практике. То есть напишем обработку с двумя табличными частями. В одной табличной части будет таблица значений с данными, а во второй дерево значений, построенное по данным таблицы.
В таблице значений у нас будут следующие поля:

  • Код
  • УровеньВложенности
  • Наименование

Поле Уровень вложенности необязательно, но оно облегчит нам многие операции с деревом.

Дерево значений будет содержать всего два поля:

  • Код
  • Наименование

В процедуре ПриСозданииНаСервере сделаем первоначальное заполнение таблицы значений, чтобы получилась вот такая картина:
Таблица иерархии
После заполнения дерева значений по данным таблицы у нас должна получится вот такая картина:

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


&НаСервере
Функция ПолучитьЧислоРазрядовВУровне()

	Возврат 2;

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

&НаСервере
Функция ПолучитьСтепень(НомерВИерархии, ТекущийУровень, Смещенние = 0)

	ЧислоРазрядовВУровне = ПолучитьЧислоРазрядовВУровне();

	ДлинаНомера = СтрДлина(СтрЗаменить(Строка(НомерВИерархии), Символы.НПП, ""));
	Степень  = ДлинаНомера - ТекущийУровень * ЧислоРазрядовВУровне + Смещенние * ЧислоРазрядовВУровне;

	Возврат Степень;

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

&НаКлиентеНаСервере
Функция ПолучитьСледующийНомерИерархии(НомерВИерархии, Уровень)

	Степень = ПолучитьСтепень(НомерВИерархии, Уровень);
	СледующийНомер = (Цел(НомерВИерархии / Pow(10, Степень)) + 1) * Pow(10, Степень);

	Возврат СледующийНомер;

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

&НаСервере
Функция ПолучитьНомерИерархииРодителя(НомерВИерархии, Уровень)

	Степень = ПолучитьСтепень(НомерВИерархии, Уровень, 1);
	НомерРодителя  = Цел(НомерВИерархии / Pow(10, Степень)) * Pow(10, Степень);

	Возврат НомерРодителя;

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

&НаСервере
Процедура ЗаполнитьДеревоНаСервере()

	ТаблицаТоваров = ТаблицаИерархии.Выгрузить();
	ТаблицаТоваров.Сортировать("Код");

	Дерево = РеквизитФормыВЗначение("ДеревоИерархии");
	Дерево.Строки.Очистить();
	ТекущийУровень= 0;

	Для каждого СтрокаТаблицы Из ТаблицаТоваров Цикл

		Если СтрокаТаблицы.УровеньВложенности = 1 Тогда

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

		ИначеЕсли СтрокаТаблицы.УровеньВложенности > ТекущийУровень Тогда

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

		ИначеЕсли СтрокаТаблицы.УровеньВложенности < ТекущийУровень Тогда

			НомерРодителя = ПолучитьНомерИерархииРодителя(СтрокаТаблицы.Код, СтрокаТаблицы.УровеньВложенности);

			Родитель = ДеревоИерархии.Строки.Найти(НомерРодителя, "Код", Истина);
			ТекущаяСтрока = Родитель.Строки.Добавить();

		Иначе

			ТекущаяСтрока = ТекущаяСтрока.Родитель.Строки.Добавить();

		КонецЕсли;

		ТекущийУровень = СтрокаТаблицы.УровеньВложенности;
		ЗаполнитьЗначенияСвойств(ТекущаяСтрока, СтрокаТаблицы);

	КонецЦикла;

	ЗначениеВРеквизитФормы(Дерево, "ДеревоИерархии");

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

&НаКлиенте
Процедура ЗаполнитьДерево(Команда)
	ЗаполнитьДеревоНаСервере();
КонецПроцедуры




Изначально при нажатии на кнопку «Заполнить дерево» вызывается процедура ЗаполнитьДерево(), которая в свою очередь вызывает процедуру ЗаполнитьДеревоНаСервере(), где и происходит непосредственно построение дерева по данным таблицы. При этом задействуется функция ПолучитьНомерИерархииРодителя() в которой по иерархическому коду дочернего элемента мы можем получить иерархический код родителя. При манипуляциях с иерархическим кодом используется возведение числа 10 в различные степени. Для получения необходимой степени используем функцию ПолучитьСтепень(). Функция ПолучитьЧислоРазрядовВУровне() возвращает количество разрядов, которое используется для каждого уровня иерархии. Поскольку мы решили выделить два знака на каждый уровень, функция просто возвращает число 2. При необходимости увеличить количество разрядов на каждый уровень — нужно просто возвращать из этой функции соответствующее число. Функция ПолучитьСледующийНомерИерархии() не используется при построении дерева и представлена как некий бонус, если кто-то захочет получить очередной иерархический код на том же уровне, что и текущий.

Заключение

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

   

2014 - 2019г. Профессия — 1С. Обмен опытом по программированию в 1С