Print
Category: Все материалы
Hits: 8084

User Rating: 0 / 5

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

Привет

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

Надо это может быть для отображения дерева на форме или вывода отчета, случаи в жизни бывают разные.

Задача звучит тривиально, т.к. в 1С все продумано для отображения иерархии справочников: динамические списки, СКД, запросы - везде есть все для работы с иерархией, но есть несколько НО, которые я и хочу устранить. Вот список этих "НО":

1. 1С нам выдает дерево, где корень не выбранный элемент, а самый верхний.

2. В случае с иерархией элементов в дереве выгруженного из запроса лезут дубли. Каждый элемент является итоговой записью и детальной записью.

Вроде мелочи, но видеть на экране лишние строки не хочется. На экран надо выдавать только информацию по делу.

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

 



Я создал базу со справочником "Этапы работ" с иерархией элементов.

в 1С Предприятии создаём справочник с иерархией элементов

и вбил туда следующую структуру:

в 1С предприятие заполняем справочник с иерархией элементов

ну такая фантазия у меня :)

И так, допустим нам нужны этапы по внедрению 1С в ООО "РиК". Т.е. вот примерно, что я бы хотел увидеть в дереве:

1С Предприятие часть данных из иерархического справочника, котрую надо получить в дерево значений

Ни самых корневых элементов, ни дублей, а чисто ту ветвь иерархии, которую я выбрал.

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

1. Самый простой

 



ВЫБРАТЬ
Этапы.Ссылка
ИЗ
Справочник.Этапы КАК Этапы
ГДЕ
Этапы.Ссылка В ИЕРАРХИИ(&ВыбранныйЭтап)

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

2. Делаем итоги по полю "Ссылка"

ВЫБРАТЬ
Этапы.Ссылка КАК Ссылка
ИЗ
Справочник.Этапы КАК Этапы
ГДЕ
Этапы.Ссылка В ИЕРАРХИИ(&ВыбранныйЭтап)
ИТОГИ ПО
Ссылка

результат удручающий, показывать пользователю это нельзя

1С Предприятие запрос с иерархией элементов выдает дубли

3. Делаем итоги по иерархии и элементам

ВЫБРАТЬ
Этапы.Ссылка КАК Ссылка
ИЗ
Справочник.Этапы КАК Этапы
ГДЕ
Этапы.Ссылка В ИЕРАРХИИ(&ВыбранныйЭтап)
ИТОГИ ПО
Ссылка ИЕРАРХИЯ

Это уже похоже на желаемый результат, тут есть иерархия, но сомтреть на это все еще страшно:

1С Предприятие запрос с итогами по элементам и иерархии выдает дубли

4. Делаем итоги только с иерархией

ВЫБРАТЬ
Этапы.Ссылка КАК Ссылка
ИЗ
Справочник.Этапы КАК Этапы
ГДЕ
Этапы.Ссылка В ИЕРАРХИИ(&ВыбранныйЭтап)
ИТОГИ ПО
Ссылка ТОЛЬКО ИЕРАРХИЯ

Опа, мусора минимум, но все еще есть дубли и есть лишние корневые элементы

1С Предприятие запрос с итогами только иерархия все равно выводит дубли

Итак, выгрузив результат запроса №4 в дерево значений мы получим нечто очень похожее на цель, но немного не то.

Первая мысль побегать по дереву кодом и убрать из него лишнее.

Вторая мысль посмотреть в сторону СКД, ведь там такого безобразия с дублями в отчетах, кажется, нет.

Пробуем отчет на СКД.

Создаем отчет с набором данных "запрос" с простейшим запросом, в котором тащим все поля какие есть:

ВЫБРАТЬ
Этапы.Ссылка,
Этапы.ВерсияДанных,
Этапы.ПометкаУдаления,
Этапы.Родитель,
Этапы.Код,
Этапы.Наименование,
Этапы.Предопределенный,
Этапы.ИмяПредопределенныхДанных
ИЗ
Справочник.Этапы КАК Этапы

В настройках тут у нас как и с запросом есть варианты:

1. Делаем группировку по полю ссылка с иерархией.

результат не супер, дубли есть, как в простом запросе

1С Предприятие отчет на СКД по справочнику с иерархией элементов выводит дубли

2. Делаем группировку по полю ссылка с только иерархией

результат хороший, дублей нет, только и листьев дерева нет :)

1С Предприятие отчет на СКД по справочнику с иерархией элементов выводит дубли

3. Делаем группировку по полю ссылка с только иерархией и добавляем детальные записи

Опять двадцать пять :(

1С Предприятие отчет на СКД по справочнику с иерархией элементов выводит дубли

Итак вывод: СКД обладает тем же косяком, что и запрос - элемент справочника выводится дважды как детальная запись и как итог для подчиненных. Да и как отсечь элементы уровнем выше выбранного - пока не понятно.

К тому же, чтобы на базе СКД программно (подразумеваем, что ни отчета, ни макета СКД в БД нет) получить дерево значений, надо в коде очень много создавать сущностей. Одно только программное создание макета чего нам будет стоить. Читабельность этого кода будет стремиться к 0.

Что же делать?

Делать будем кодом, осталось выбрать подход. Хочется взять запрос №4, выгрузить его в дерево и дальше его обрабатывать, но есть у дерева значений минусы:

1. Нельзя менять родителя ветки. А это помогло бы нам найти в дереве строку с выбранным элементом и кинуть её в корень. Но таких методов нет. Поле "Родитель" у строки дерева только для чтения.

2. Как убрать дубли? Технически строки дублей абсолютно идентичны. Какую удалять? И куда деть подчиненные строки у удаляемой, а они иногда есть.

Я принял решение: запрос №1 без всяких итогов. Т.к. дерево один фиг придется строить с нуля, его проще строить на базе линейной тз, т.к. её проще перебирать. Все созданные ветки будем кэшировать в соответсвии. Родителя каждого элемента получим сразу в запросе, чтобы не было обращений к БД внутри цикла. Строить будем рекурсивно. Строку добавляем на возврате из рекурсии, чтобы родительская ветка уже была в дереве.

Вот код с комментариями, если есть мысли как сделать этот кусок кода "чище" или "изящнее" или "понятнее" пишите в комментах к статье:

&НаСервере

//точка входа основная процедура формирующая дерево

Процедура СформироватьНаСервере()

//1. Создадим дерево с одной строкой в корне

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

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

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

//этап - переменная формы, которую выбрали в поле ввода

Корень.Этап= Этап;

//2. Найдем все подчиненные этапы работ

Запрос = Новый Запрос("ВЫБРАТЬ

                     |ЭтапыРабот.Ссылка,

                     |ЭтапыРабот.Родитель

                     |ИЗ

                     |Справочник.ЭтапыРабот КАК ЭтапыРабот

                     |ГДЕ

                     |ЭтапыРабот.Ссылка В ИЕРАРХИИ(&корень)");

Запрос.УстановитьПараметр("корень", Этап);

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

тз = рез.Выгрузить();

КэшУжеПрописаных = Новый Соответствие;

КэшУжеПрописаных.Вставить(Этап, Корень);

Для Каждого стр Из тз Цикл

 

СунутьВНужнуюВеткуДерева(Корень, КэшУжеПрописаных, тз, стр);

КонецЦикла;

//КОНЕЦ, в переменной дерево лежит нужное нам дерево

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

 

&НаСервере

Процедура СунутьВНужнуюВеткуДерева(Корень, КэшУжеПрописаных, тз, обрабатываемаяСтрока)

//ищем в кэше саму ссылку

КэшСсылки = КэшУжеПрописаных.Получить(обрабатываемаяСтрока.Ссылка);

Если КэшСсылки<>Неопределено тогда

Возврат;

КонецЕсли;

 

//отправляем в рекурсию родителя

//для этого в тз ищем строку с родителем, это чтобы не искать через точку

мСтрокСРодителем = тз.НайтиСтроки(Новый Структура("Ссылка", обрабатываемаяСтрока.Родитель));

Для Каждого СтрокаТзСРодителем Из мСтрокСРодителем Цикл

СунутьВНужнуюВеткуДерева(Корень, КэшУжеПрописаных, тз, СтрокаТзСРодителем);

КонецЦикла;

 

//ищем в кэше родителя, его там не может не быть!!!, но мы проверим

КэшРодителя = КэшУжеПрописаных.Получить(обрабатываемаяСтрока.Родитель);

Если КэшРодителя<>Неопределено тогда

//добавляем в найденную ветку в кэше ссылку

ДобавляемаяСтрока = КэшРодителя.Строки.Добавить();

ДобавляемаяСтрока.Этап= обрабатываемаяСтрока.Ссылка;

//кэшируем новую строку

КэшУжеПрописаных.Вставить(обрабатываемаяСтрока.Ссылка, ДобавляемаяСтрока);

КонецЕсли;

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

 

 Во вложении dt файл со всем о чем тут шла речь.

Там справочник этапов, консоль запросов, отчет на СКД с 3мя вариантами и обработка с моим решением

Вложения
Download this file (TestTrees.dt)TestTrees.dt[TestTrees.dt]88 kB