Синтаксис и применение Упорядочивание по иерархии в платформе 1С:Предприятие. Описание и примеры кода.
Полное описание, параметры и ограничения
Упорядочивание по иерархии
Для иерархических данных (справочников) можно назначать упорядочивание по иерархии.
Пример:
ВЫБРАТЬ
Справочник.Контрагенты.Наименование,
Справочник.Контрагенты.Полноенаименование
УПОРЯДОЧИТЬ ПО
Справочник.Контрагенты.Наименование Иерархия
Результат запроса:
Наименование
ПолноеНаименование
Покупатели
Павильон 45 на оптовом рынке
ПБЮЛ "Красина"
Торговый дом "Буденовский"
АО "Буденовский ТД"
Фабрика джинсовой одежды
ООО "Джинсовая одежда"
Ярмарка одежды
ООО "Ярмарка одежды"
Поставщики
АКБ ПромСтройБанк
Бавария – фарфор
Трикотажная фабрика "Заря"
Фабрика джинсовой одежды
ООО "Джинсовая одежда"
Иерархически сортировать можно только по полю, но не по некоторой операции над ним: <Поле упорядочивания> должно содержать ссылку на поле исходной таблицы – источника данных запроса.
Важно понимать, что упорядочивание по иерархии имеет смысл задавать в том случае, если в качестве источника определена именно таблица справочника, а не какая-либо другая таблица, содержащая только ссылку на справочник.
Пример:
ВЫБРАТЬ
Накладная.Контрагент.Наименование,
Накладная.Номер,
Накладная.Сумма
ИЗ
Документ.РасходнаяНакладная КАК Накладная
УПОРЯДОЧИТЬ ПО
Накладная.Контрагент ИЕРАРХИЯ
В данном примере иерархического упорядочивания не получится, поскольку нет связи со справочником, и группы из этого справочника в результат запроса не попадут.
Для упорядочивания по иерархии необходимо организовать соединение со справочником.
Пример:
ВЫБРАТЬ
Контрагент.Наименование,
Накладная.Номер,
Накладная.Сумма
ИЗ
Справочник.Контрагенты КАК Контрагент
ЛЕВОЕ СОЕДИНЕНИЕ
Документ.РасходнаяНакладная КАК Накладная
ПО
Накладная.Контрагент = Контрагент.Ссылка
УПОРЯДОЧИТЬ ПО
Контрагент.Наименование Иерархия
Результат запроса:
Наименование
Номер
Сумма
Покупатели
Павильон 45 на оптовом рынке
00007
6 000
Павильон 45 на оптовом рынке
00006
11 500
Павильон 45 на оптовом рынке
00016
80 000,23
Торговый дом "Буденовский"
00004
1 500
Торговый дом "Буденовский"
00003
52 500
Торговый дом "Буденовский"
00002
16 000
Торговый дом "Буденовский"
00009
555
Торговый дом "Буденовский"
00015
Торговый дом "Буденовский"
00014
16 500
Торговый дом "Буденовский"
00005
1 500
Фабрика джинсовой одежды
Ярмарка одежды
00001
54 000
Поставщики
АКБ ПромСтройБанк
Бавария – фарфор
00013
12 000,22
Трикотажная фабрика "Заря"
00012
4 500
Фабрика джинсовой одежды
Практические примеры
ИЕРАРХИЯ в сортировке: сохранить ветви пяти своих настоящих узлов
Пять собственных реальных записей имеют имена, которые разрывают ветви при обычной сортировке. Два полных результата сравниваются с независимыми ожиданиями, а исходники сохраняются до rollback.
Где и как запускать
Полный серверный общий модуль УчебныйЯзык только нового собственного стенда УчебныеИерархическиеИтоги85 на 8.5.1.1343. BSL, запросы и транзакции здесь не исполнялись.
Подготовка
В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.
Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.
В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.
HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.
Создайте НОВУЮ отдельную пустую учебную базу, не копию приложения, на точной 8.5.1.1343. Конфигурация УчебныеИерархическиеИтоги85; совместимость отключена; единственный сеанс. Нет расширений базы/сеанса, подписок, общих реквизитов, документов, регистров, планов, последовательностей, фоновых заданий или внешних источников данных. Ошибки прав/схемы не являются ожидаемым результатом опыта.
Справочники → УчебноеДерево85: Иерархический=Да; Вид иерархии=Иерархия групп и элементов; Ограничивать количество уровней=Нет; Владельцы пусты. Код только Строка, длина3; Автонумерация=Нет; Наименование длина20. Собственных реквизитов, табчастей и предопределённых элементов нет. Стандартные поля платформы остаются.
Все объектные/менеджерские модули, формы, модули сеанса/приложения и обработчики вручную полностью пусты. Native МодульОбъекта и МодульМенеджера всегда Неопределено и не позволяют прочитать текст BSL: guard не выдаёт это значение за доказательство пустого модуля. Это обязательная проверка читателя в новом Конфигураторе; здесь Конфигуратор не запускался.
Read-only guard проверяет минимальную схему, пустой ФиксированныйМассив предопределённых имён, пустые массивы трёх источников расширений БазаДанных/СеансАктивные/СеансОтключенные и отсутствие изменений метаданных расширениями. До действий запрещена чужая/вложенная транзакция и проверен Число0 собственных записей без их удаления.
Основной код целиком заменяет свой серверный общий модуль УчебныйЯзык; все helpers расположены рядом с экспортной процедурой, не внутри неё. У модуля Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь; клиентские/внешнее соединение отключены, повторное использование выключено. Для следующего урока замените модуль целиком, не объединяйте одноимённые экспортные точки.
Новая собственная внешняя обработка УчебныйПускИерархическогоПорядка85 → управляемая Форма → команда Выполнить и кнопка с одноимённым действием. Остальные модули пусты. Полный отдельный модуль формы:
&НаКлиенте
Процедура Выполнить(Команда)
ВыполнитьНаСервере();
Сообщить("Полные собственные проверки завершены; учебных записей не осталось");
КонецПроцедуры&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
УчебныйЯзык.ВыполнитьПример();
КонецПроцедурыБудущий авторский BSL записывает ровно свои5узлов только внутри своей транзакции; не фиксирует её, не проводит/удаляет объекты. При успехе и ошибке обязательны собственный rollback и проверка завершения транзакции/отсутствия своих записей. Ничего заранее вручную не записывайте.
Python моделирует только фиксированные входы, полные ожидания и нашу проверку состава/дерева. Direct HBK подтверждает нативный текст установленной версии, но ни он, ни focused/static tests не доказывают исполнение BSL/запросов/отката в 1С.
Общий обязательный этап перед первым ручным запуском каждого урока: после ВСЕХ настроек метаданных, флагов общего модуля, вставки полного основного модуля и подготовки полного модуля своей формы сохраните свою конфигурацию. Завершите свой предыдущий учебный сеанс; активной транзакции и выполняющегося учебного опыта быть не должно. В Конфигураторе своего стенда выполните Конфигурация → Обновить конфигурацию базы данных (F7), подтвердите только изменения своей новой учебной конфигурации и дождитесь успешного завершения обновления. Затем запустите свежий учебный сеанс и только в нём нажимайте Выполнить. Здесь F7 означает только обновление конфигурации базы данных автором стенда ДО ручного запуска, никогда не аварийный опыт и не действие после пяти Записать внутри активной транзакции. Сохранение/обновление/1С здесь не выполнялись.
Отдельный будущий ручной опыт «Контроль аварийного отката» выполняется только после обычного положительного опыта и подтверждённого Число0 в своей новой базе. Завершите положительный опыт и свой учебный сеанс до редактирования модуля. В Конфигураторе → Общие → Общие модули → УчебныйЯзык → Модуль временно вставьте ровно одну строку ВызватьИсключение "Учебная авария после пяти собственных записей"; сразу после строки ЛистЗ = СоздатьСвойУзел("201", "A-Z", ГруппаБ, Ложь, СвоиРодители); внутри Попытка экспортной ВыполнитьПример и до ОжиданияКаталога = Новый Массив. При будущем выполнении к этому месту завершатся ровно5собственных Записать; рабочие запросы/сверка каталога ещё не начнутся. Позиция строки BSL не означает обновление конфигурации во время опыта. Не вставляйте ошибку внутрь валидатора или его локального catch.
Подготовка «Контроля аварийного отката» после временной вставки: сохраните свою конфигурацию и вне активной транзакции/до нового ручного запуска выполните Конфигурация → Обновить конфигурацию базы данных (F7). Дождитесь успешного обновления и запустите свежий учебный сеанс. Не обновляйте конфигурацию после пяти Записать или при остановленном в активной транзакции серверном коде: там исполняется уже подготовленная строка ВызватьИсключение, а не обновление конфигурации.
«Контроль аварийного отката»: включите серверную отладку своей базы и поставьте останов в ПроверитьОтсутствиеСвоихЗаписей при вызове из аварийной очистки после ОтменитьТранзакцию, не на предварительный вызов до НачатьТранзакцию. После нажатия Выполнить продолжите исходную контролируемую ошибку через внешний Исключение. Здесь ТранзакцияАктивна() должна быть Булево Ложь; в собственной ПроверитьОтсутствиеСвоихЗаписей после Выполнить().Выгрузить() проверьте фактические Таблица.Количество()=1, одну колонку Количество и Таблица[0].Количество=Число0. Это actual readback нового собственного справочника вне транзакции, не обещание модели Python.
«Контроль аварийного отката»: после завершения аварийной очистки вызов обязан закончиться ошибкой, а не сообщениями успешного опыта или launcher «Полные собственные проверки завершены». Если rollback/readback/Закрыть тоже отказали, фиксируйте фактическую диагностику и неподтверждённую очистку, не считайте контроль аварийного отката пройденным и не обновляйте конфигурацию при активном опыте. Завершите свой учебный сеанс до изменения модуля. Удалите только свою временную строку исключения из своего общего модуля, восстановите полный исходный положительный текст, сохраните конфигурацию и вне активной транзакции выполните Конфигурация → Обновить конфигурацию базы данных (F7). Дождитесь успешного обновления, затем запустите свежий учебный сеанс для отдельного повторения положительного опыта; ничего не удаляйте из базы. Контроль аварийного отката/отладчик/1С здесь не запускались.
Процедура ВыполнитьПример() Экспорт
ПроверитьСвойИерархическийСтенд();
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция запрещена";
КонецЕсли;
ПроверитьОтсутствиеСвоихЗаписей();
НачатьТранзакцию();
Попытка
ПустойРодитель = Справочники.УчебноеДерево85.ПустаяСсылка();
СвоиРодители = Новый Массив;
СвоиРодители.Добавить(ПустойРодитель);
ПроверитьСвойВводУзла("001", "A", ПустойРодитель, Истина, СвоиРодители);
ПроверитьСвойВводУзла("999", "12345678901234567890", ПустойРодитель, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла(Неопределено, "A", ПустойРодитель, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("001", 7, ПустойРодитель, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("01", "A", ПустойРодитель, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("001", "", ПустойРодитель, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("001", "A", Неопределено, Истина, СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("001", "A", ПустойРодитель, "Истина", СвоиРодители);
ПроверитьОтклонениеСвоегоУзла("001", "A", ПустойРодитель, Ложь, СвоиРодители);
ПроверитьОтказУровняПустойСсылки(ПустойРодитель);
ГруппаА = СоздатьСвойУзел("100", "B-A", ПустойРодитель, Истина, СвоиРодители);
СвоиРодители.Добавить(ГруппаА);
ГруппаБ = СоздатьСвойУзел("200", "C-B", ПустойРодитель, Истина, СвоиРодители);
СвоиРодители.Добавить(ГруппаБ);
ЛистХ = СоздатьСвойУзел("101", "A-X", ГруппаА, Ложь, СвоиРодители);
ЛистУ = СоздатьСвойУзел("102", "D-Y", ГруппаА, Ложь, СвоиРодители);
ЛистЗ = СоздатьСвойУзел("201", "A-Z", ГруппаБ, Ложь, СвоиРодители);
ОжиданияКаталога = Новый Массив;
ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаА, "100", "B-A", ПустойРодитель, Истина));
ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистХ, "101", "A-X", ГруппаА, Ложь));
ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистУ, "102", "D-Y", ГруппаА, Ложь));
ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаБ, "200", "C-B", ПустойРодитель, Истина));
ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистЗ, "201", "A-Z", ГруппаБ, Ложь));
ПроверитьСвойКаталожныйСостав(ОжиданияКаталога);
Поля = Новый Массив;
Поля.Добавить("Ссылка");
Поля.Добавить("Код");
Поля.Добавить("Наименование");
Поля.Добавить("Родитель");
Поля.Добавить("ЭтоГруппа");
ОжиданияИерархии = Новый Массив;
ОжиданияИерархии.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаА, "100", "B-A", ПустойРодитель, Истина));
ОжиданияИерархии.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистХ, "101", "A-X", ГруппаА, Ложь));
ОжиданияИерархии.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистУ, "102", "D-Y", ГруппаА, Ложь));
ОжиданияИерархии.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаБ, "200", "C-B", ПустойРодитель, Истина));
ОжиданияИерархии.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистЗ, "201", "A-Z", ГруппаБ, Ложь));
ОжиданияПлоского = Новый Массив;
ОжиданияПлоского.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистХ, "101", "A-X", ГруппаА, Ложь));
ОжиданияПлоского.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистЗ, "201", "A-Z", ГруппаБ, Ложь));
ОжиданияПлоского.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаА, "100", "B-A", ПустойРодитель, Истина));
ОжиданияПлоского.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаБ, "200", "C-B", ПустойРодитель, Истина));
ОжиданияПлоского.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистУ, "102", "D-Y", ГруппаА, Ложь));
Иерархический = Новый Запрос;
Иерархический.Текст = "ВЫБРАТЬ Кат.Ссылка КАК Ссылка, Кат.Код КАК Код, Кат.Наименование КАК Наименование,
|Кат.Родитель КАК Родитель, Кат.ЭтоГруппа КАК ЭтоГруппа
|ИЗ Справочник.УчебноеДерево85 КАК Кат
|УПОРЯДОЧИТЬ ПО Кат.Наименование ИЕРАРХИЯ";
ТаблицаИерархии = Иерархический.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой);
ПроверитьСвоюПолнуюТаблицу(ТаблицаИерархии, ОжиданияИерархии, Поля, Истина);
Плоский = Новый Запрос;
Плоский.Текст = "ВЫБРАТЬ Кат.Ссылка КАК Ссылка, Кат.Код КАК Код, Кат.Наименование КАК Наименование,
|Кат.Родитель КАК Родитель, Кат.ЭтоГруппа КАК ЭтоГруппа
|ИЗ Справочник.УчебноеДерево85 КАК Кат
|УПОРЯДОЧИТЬ ПО Кат.Наименование ВОЗР";
ТаблицаПлоская = Плоский.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой);
ПроверитьСвоюПолнуюТаблицу(ТаблицаПлоская, ОжиданияПлоского, Поля, Истина);
Неверный = Новый Запрос;
Неверный.Текст = "ВЫБРАТЬ Кат.Ссылка КАК Ссылка, Кат.Код КАК Код, Кат.Наименование КАК Наименование,
|Кат.Родитель КАК Родитель, Кат.ЭтоГруппа КАК ЭтоГруппа
|ИЗ Справочник.УчебноеДерево85 КАК Кат
|УПОРЯДОЧИТЬ ПО Кат.Наименование + """" ИЕРАРХИЯ";
Отклонён = Ложь;
Попытка
Неверный.Выполнить();
Исключение
Отклонён = Истина;
Сообщить("Ручной native опыт: операция над полем не допускает ИЕРАРХИЯ. " + ОписаниеОшибки());
КонецПопытки;
Если Не Отклонён Тогда
ВызватьИсключение "Ожидалось отклонение операции над полем иерархической сортировки";
КонецЕсли;
ПроверитьСвойКаталожныйСостав(ОжиданияКаталога);
Сообщить("Все поля и порядок: иерархия A,X,Y,B,Z; плоско X,Z,A,B,Y; каталожные уровни групп0/листов1");
Исключение
Если ТранзакцияАктивна() Тогда
ОтменитьТранзакцию();
КонецЕсли;
ПроверитьОтсутствиеСвоихЗаписей();
ВызватьИсключение;
КонецПопытки;
ОтменитьТранзакцию();
ПроверитьОтсутствиеСвоихЗаписей();
Сообщить("Пять своих записей отменены; новый собственный справочник снова пуст");
КонецПроцедуры
Процедура ПроверитьСвойИерархическийСтенд()
Если Метаданные.Справочники.Количество() <> 1 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый минимальный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Метаданные своего сеанса не должны изменяться расширениями";
КонецЕсли;
ИсточникиРасширений = Новый Массив;
ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого ИсточникРасширений Из ИсточникиРасширений Цикл
СписокРасширений = РасширенияКонфигурации.Получить(, ИсточникРасширений);
Если ТипЗнч(СписокРасширений) <> Тип("Массив") Тогда
ВызватьИсключение "Список расширений должен иметь native тип Массив";
КонецЕсли;
Если СписокРасширений.Количество() <> 0 Тогда
ВызватьИсключение "В новом своём стенде не должно быть расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
МетаДерево = Метаданные.Справочники.Найти("УчебноеДерево85");
Если МетаДерево = Неопределено Тогда
ВызватьИсключение "Не найден свой справочник УчебноеДерево85";
КонецЕсли;
Свойства = Метаданные.СвойстваОбъектов;
Если Не МетаДерево.Иерархический Или МетаДерево.ВидИерархии <> Свойства.ВидИерархии.ИерархияГруппИЭлементов
Или МетаДерево.ОграничиватьКоличествоУровней Или МетаДерево.Владельцы.Количество() <> 0
Или МетаДерево.ТипКода <> Свойства.ТипКодаСправочника.Строка Или МетаДерево.ДлинаКода <> 3
Или МетаДерево.ДлинаНаименования <> 20 Или МетаДерево.Автонумерация
Или МетаДерево.Реквизиты.Количество() <> 0 Или МетаДерево.ТабличныеЧасти.Количество() <> 0 Тогда
ВызватьИсключение "Не совпала своя минимальная схема иерархии";
КонецЕсли;
Имена = МетаДерево.ПолучитьИменаПредопределенных();
Если ТипЗнч(Имена) <> Тип("ФиксированныйМассив") Тогда
ВызватьИсключение "Предопределённые имена должны иметь native тип ФиксированныйМассив";
КонецЕсли;
Если Имена.Количество() <> 0 Тогда
ВызватьИсключение "В своём справочнике нет предопределённых имён";
КонецЕсли;
КонецПроцедуры
Функция ПолностьюСовпадаетСвояСтрока(СтрокаТаблицы, Ожидаемая, Поля, Колонки)
Для Каждого ИмяПоля Из Поля Цикл
Если Не Ожидаемая.Свойство(ИмяПоля, Ожидание) Тогда
ВызватьИсключение "Не найдено полное собственное ожидание поля " + ИмяПоля;
КонецЕсли;
Колонка = Колонки.Найти(ИмяПоля);
Факт = СтрокаТаблицы.Получить(Колонки.Индекс(Колонка));
Если ТипЗнч(Факт) <> ТипЗнч(Ожидание) Тогда
Возврат Ложь;
КонецЕсли;
Если Факт <> Ожидание Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Процедура ПроверитьСвоюПолнуюТаблицу(Таблица, Ожидания, Поля, Упорядоченный)
Если ТипЗнч(Таблица) <> Тип("ТаблицаЗначений") Тогда
ВызватьИсключение "Нужна своя ТаблицаЗначений";
КонецЕсли;
Если Таблица.Колонки.Количество() <> Поля.Количество() Или Таблица.Количество() <> Ожидания.Количество() Тогда
ВызватьИсключение "Не совпали полные размеры своей таблицы";
КонецЕсли;
Для Каждого ИмяПоля Из Поля Цикл
Если Таблица.Колонки.Найти(ИмяПоля) = Неопределено Тогда
ВызватьИсключение "Не найдена своя колонка " + ИмяПоля;
КонецЕсли;
КонецЦикла;
Использованные = Новый Массив;
Если Ожидания.Количество() > 0 Тогда
Для Индекс = 0 По Ожидания.Количество() - 1 Цикл
Если Упорядоченный Тогда
Если Не ПолностьюСовпадаетСвояСтрока(Таблица[Индекс], Ожидания[Индекс], Поля, Таблица.Колонки) Тогда
ВызватьИсключение "Не совпали все поля, типы или порядок своей строки";
КонецЕсли;
Иначе
Найден = -1;
Для Кандидат = 0 По Ожидания.Количество() - 1 Цикл
Если Использованные.Найти(Кандидат) = Неопределено Тогда
Если ПолностьюСовпадаетСвояСтрока(Таблица[Индекс], Ожидания[Кандидат], Поля, Таблица.Колонки) Тогда
Найден = Кандидат;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Найден = -1 Тогда
ВызватьИсключение "Не совпал полный свой unordered состав с кратностями";
КонецЕсли;
Использованные.Добавить(Найден);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьОтсутствиеСвоихЗаписей()
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Пустота своей базы проверяется вне транзакции";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Количество ИЗ Справочник.УчебноеДерево85";
Таблица = Запрос.Выполнить().Выгрузить();
Если Таблица.Количество() <> 1 Или Таблица.Колонки.Количество() <> 1
Или Таблица.Колонки.Найти("Количество") = Неопределено Тогда
ВызватьИсключение "Не совпала полная форма собственного счётчика";
КонецЕсли;
Если ТипЗнч(Таблица[0].Количество) <> Тип("Число") Тогда
ВызватьИсключение "Свой счётчик должен иметь тип Число";
КонецЕсли;
Если Таблица[0].Количество <> 0 Тогда
ВызватьИсключение "Новая собственная база должна быть пустой; код ничего не удаляет";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
Если ТипЗнч(Код) <> Тип("Строка") Или ТипЗнч(Наименование) <> Тип("Строка") Тогда
ВызватьИсключение "Собственные код и наименование должны иметь тип Строка";
КонецЕсли;
Если СтрДлина(Код) <> 3 Или СтрДлина(Наименование) < 1 Или СтрДлина(Наименование) > 20 Тогда
ВызватьИсключение "Собственный код имеет длину3, имя1..20";
КонецЕсли;
Если ТипЗнч(Родитель) <> Тип("СправочникСсылка.УчебноеДерево85") Или ТипЗнч(ЭтоГруппа) <> Тип("Булево")
Или ТипЗнч(СвоиРодители) <> Тип("Массив") Тогда
ВызватьИсключение "Не совпали собственные типы родителя, признака группы или списка родителей";
КонецЕсли;
Если СвоиРодители.Найти(Родитель) = Неопределено Тогда
ВызватьИсключение "Родитель должен принадлежать данному собственному fixture";
КонецЕсли;
Пустой = Справочники.УчебноеДерево85.ПустаяСсылка();
Если ЭтоГруппа И Родитель <> Пустой Тогда
ВызватьИсключение "Наши две группы расположены только в корне";
КонецЕсли;
Если Не ЭтоГруппа И Родитель = Пустой Тогда
ВызватьИсключение "Наши три элемента располагаются только в своих группах";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьОтклонениеСвоегоУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
Отклонён = Ложь;
Попытка
ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители);
Исключение
Отклонён = Истина;
Сообщить("Ручной опыт: свой неверный ввод узла отклонён. " + ОписаниеОшибки());
КонецПопытки;
Если Не Отклонён Тогда
ВызватьИсключение "Ожидалось отклонение данного собственного ввода узла";
КонецЕсли;
КонецПроцедуры
Функция СоздатьСвойУзел(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители);
Если ЭтоГруппа Тогда
Объект = Справочники.УчебноеДерево85.СоздатьГруппу();
Иначе
Объект = Справочники.УчебноеДерево85.СоздатьЭлемент();
КонецЕсли;
Если ТипЗнч(Объект.ЭтоГруппа) <> Тип("Булево") Или Объект.ЭтоГруппа <> ЭтоГруппа Тогда
ВызватьИсключение "Native readonly ЭтоГруппа не совпало с выбранной фабрикой";
КонецЕсли;
Объект.Код = Код;
Объект.Наименование = Наименование;
Объект.Родитель = Родитель;
Объект.Записать();
Ссылка = Объект.Ссылка;
Если ТипЗнч(Ссылка) <> Тип("СправочникСсылка.УчебноеДерево85") Тогда
ВызватьИсключение "После записи нужна собственная ссылка узла";
КонецЕсли;
Если Ссылка = Справочники.УчебноеДерево85.ПустаяСсылка() Тогда
ВызватьИсключение "Своя записанная ссылка не должна быть пустой";
КонецЕсли;
Возврат Ссылка;
КонецФункции
Процедура ПроверитьСвойКаталожныйСостав(Ожидания)
Проверка = Новый Запрос;
Проверка.Текст = "ВЫБРАТЬ Кат.Ссылка КАК Ссылка, Кат.Код КАК Код, Кат.Наименование КАК Наименование,
|Кат.Родитель КАК Родитель, Кат.ЭтоГруппа КАК ЭтоГруппа
|ИЗ Справочник.УчебноеДерево85 КАК Кат УПОРЯДОЧИТЬ ПО Кат.Код ВОЗР";
Поля = Новый Массив;
Поля.Добавить("Ссылка");
Поля.Добавить("Код");
Поля.Добавить("Наименование");
Поля.Добавить("Родитель");
Поля.Добавить("ЭтоГруппа");
Таблица = Проверка.Выполнить().Выгрузить();
ПроверитьСвоюПолнуюТаблицу(Таблица, Ожидания, Поля, Истина);
Для Каждого Строка Из Таблица Цикл
УровеньКаталога = Строка.Ссылка.Уровень();
Если ТипЗнч(УровеньКаталога) <> Тип("Число") Тогда
ВызватьИсключение "Native уровень своей непустой ссылки должен иметь тип Число";
КонецЕсли;
Если Строка.ЭтоГруппа Тогда
Если УровеньКаталога <> 0 Тогда
ВызватьИсключение "Своя группа без родителя должна иметь каталожный уровень0";
КонецЕсли;
Иначе
Если УровеньКаталога <> 1 Тогда
ВызватьИсключение "Свой лист под корневой группой должен иметь каталожный уровень1";
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ПроверитьОтказУровняПустойСсылки(Пустая)
Отклонён = Ложь;
Попытка
Пустая.Уровень();
Исключение
Отклонён = Истина;
Сообщить("Ручной native опыт: Уровень пустой ссылки вызвал исключение. " + ОписаниеОшибки());
КонецПопытки;
Если Не Отклонён Тогда
ВызватьИсключение "По native вызов Уровень пустой ссылки должен вызвать исключение";
КонецЕсли;
КонецПроцедурыУчебныйПускИерархическогоПорядка85.Форма
Собственная новая внешняя обработка УчебныйПускИерархическогоПорядка85 → управляемая Форма → Модуль
Полный отдельный клиентский/серверный модуль формы; серверная процедура без контекста вызывает свой серверный общий модуль. Не смешивать с основным модулем.
&НаКлиенте
Процедура Выполнить(Команда)
ВыполнитьНаСервере();
Сообщить("Полные собственные проверки завершены; учебных записей не осталось");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
УчебныйЯзык.ВыполнитьПример();
КонецПроцедурыРазбор по шагам
Подготовить только новый собственный стенд и полный серверный модуль. Guard до действий сверяет минимальную схему и native metadata-enum вида иерархии.
Проверить конфигурационные предопределённые имена как пустой ФиксированныйМассив. Read-only список расширений проверяется для всех3native источников, не только базы; изменения метаданных расширениями не допускаются.
Пустые модули/формы и единственный сеанс — обязательная ручная подготовка. Native-свойства модулей всегда Неопределено: нельзя на основании этого обещать отсутствие обработчиков.
До действий запретить активную чужую/вложенную транзакцию и непустой собственный источник без очистки. После обеих ветвей проверить отсутствие своих записей вне транзакции; полный запуск дан отдельно от общего модуля.
Свой ввод узла проверяется до СоздатьГруппу/СоздатьЭлемент: типы кода/имени/родителя/Булево, длины и принадлежность родителя своему fixture. Две границы принимаются, семь плохих вводов отклоняются только своим валидатором.
Создать две корневые группы100/B-A и200/C-B; под первой листья101/A-X и102/D-Y, под второй201/A-Z. Это настоящие Родитель/ЭтоГруппа/Ссылка после своих Записать, не плоская таблица, имитирующая иерархию.
Исходный запрос по коду сверяет все5полей каждой из5записей. Native СправочникСсылка.Уровень возвращает Число, для элемента без родителя прямо указан0; свои группы должны иметь0, листья под ними1. Пустая ссылка по native вызывает исключение; catch только вокруг намеренного вызова Уровень.
Рабочий источник — сама таблица Справочник.УчебноеДерево85. Условие сортировки прямо ссылается на Кат.Наименование ИЕРАРХИЯ; нет AUTOORDER и нет операции над этим полем.
Иерархический полный порядок: A100/B-A, X101/A-X, Y102/D-Y, B200/C-B, Z201/A-Z. Родители и признаки группы сохраняются; каждый дочерний блок остаётся рядом со своей группой.
Независимый контроль с Наименование ВОЗР должен дать X,Z,A,B,Y. Проверить все5полей, типы и позиции каждой строки обеих таблиц, не только список имён или количество.
Обход выгрузки явно Прямой. Иерархическая сортировка сама не превращает строки в итоговые группировки; каталожный Уровень ссылки — отдельный API, не native Уровень выборки результата.
Намеренно плохой запрос сортирует Наименование+пустаяСтрока ИЕРАРХИЯ. Native разрешает здесь только прямое поле, не операцию. Защитный catch оборачивает исключительно его Выполнить; успешные проверки/подготовка не скрываются.
Повторно проверить полный исходный состав и каталожные уровни. На успехе и ошибке отменить только свою транзакцию, проверить Число0своих записей вне неё и не удалять объектами.
Выполнение в 1С не проверялось. Python — только модель собственных фиксированных данных и проверок полного состава, не заменяет будущий ручной BSL опыт.
Отдельно в будущем выполнить «Контроль аварийного отката» по точной подготовке: контролируемая ошибка после5своих Записать и до рабочей проверки каталога/запросов должна пройти внешний catch, свой rollback и actual Число0readback. Проверить Булево Ложь активности транзакции и отсутствие сообщения успеха; затем вне опыта убрать только свою временную строку, восстановить обычный модуль, сохранить/обновить свою конфигурацию и запустить свежий учебный сеанс. Встроенные локальные negative-validator catches этот аварийный путь не проверяют.
Как проверить результат
Полные пятёрки рабочего результата A,X,Y,B,Z и плоского контроля X,Z,A,B,Y совпадают по ссылкам/кодам/именам/родителям/Булево и каждому месту.
Ссылки/родители точно СправочникСсылка.УчебноеДерево85; Код/Наименование Строка; ЭтоГруппа Булево. Исходные записи и каталожные уровни0/1 совпали до/после.
Семь собственных неверных вводов, native Уровень пустой ссылки и плохая операция сортировки имеют изолированные отрицательные проверки; catch не подменяет успех.
Guard отказался бы от неверной версии/схемы/расширения/непустоты/чужой транзакции. Свои5записей после обеих ветвей rollback отсутствуют.
Контроль аварийного отката — отдельная будущая ручная проверка внешнего аварийного пути после5Записать: ТранзакцияАктивна()=Булево Ложь, actual собственный COUNT=Число0, исходная ошибка при успешной очистке и никаких сообщений успеха. Ошибка самой очистки означает неподтверждённый контроль аварийного отката, не успех; временная строка затем убрана только из своего модуля вне опыта, конфигурация сохранена/обновлена до запуска свежего учебного сеанса.
Ожидаемый результат
Настоящее упорядочивание по иерархии отличено от обычной сортировки имён на полном собственном наборе, без предположений о порядке ссылок.
На что обратить внимание
Native модули объекта/менеджера всегда Неопределено, поэтому guard не может доказать пустой BSL текст. Пустота проверяется вручную в новом Конфигураторе; расширения не отключаются/не удаляются кодом.
Будущие собственные записи нужны только для реальной иерархии первых двух уроков. Здесь база/конфигурация/1С не исполнялись и не менялись; успешное создание/откат не заявляются.
Python моделирует только фиксированные данные, наши ожидания и проверки. Статические тесты/direct native не являются runtime доказательством.
Привязка примера только к реально применённой теме; базовые источники/агрегаты/параметры не добавляются повторно ради счётчика. ДЛЯ ИЗМЕНЕНИЯ, РАЗРЕШЕННЫЕ и РазмерХранимыхДанных разобраны в самостоятельных уроках с собственными сеансами, правами и данными. Этот урок не заменяет их отдельные задачи. Комментарии и общая грамматика также разобраны отдельно.
Ограничение диагностики: аварийная очистка вызывается до ВызватьИсключение без аргументов. Если её собственные ОтменитьТранзакцию, Закрыть менеджера ВТ или readback тоже вызывают исключение, исходная диагностика может быть заменена ошибкой очистки; сохранение исходной диагностики не обещается. Для RU/EN транзакции/записей нет, но ограничение относится к ЗакрытьСвоиВТБезЗаписей и проверке пустоты. При таком сбое фактически закрытые ВТ/откат/пустота требуют отдельной проверки, сообщение успеха не допускается. Здесь аварийные операции и диагностика не проверены runtime.
Native требует прямое поле исходной таблицы. Операция над ним не поддерживает ИЕРАРХИЯ; источник, содержащий только ссылку на справочник, не добавляет его группы.
Нулевой каталожный уровень без родителя прямо подтверждён Level260.html. Он не доказывает начальное0у Уровень выборки запроса; это другой контракт.
Все корневые соседи здесь группы, а все их дети листья; уникальные имена снимают ничьи. Не обещаются дополнительные правила для смешанных/равных соседей.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.