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

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

Зацикливание уровней в 1С: что это такое и как его устранить

Зацикливание уровней в 1С: причины циклических ссылок в иерархических справочниках и коде, способы найти и устранить зацикливание без потери данных.

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

Проблема встречается в иерархических справочниках (номенклатура, контрагенты, подразделения, статьи затрат), в планах счетов, в рекурсивных процедурах прикладного кода и при обменах данными, когда в разных базах родителя элемента назначили по-разному. Последствия варьируются от зависания отчёта и ошибки проведения документа до полной остановки фоновых заданий и невозможности открыть список справочника.

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

Что именно называют зацикливанием уровней

В иерархическом справочнике каждый элемент хранит ссылку на родителя в поле Родитель. Нормальная структура — это дерево: у каждого элемента не более одного родителя, а у корня родителя нет. Зацикливание возникает, когда, двигаясь по ссылкам «вверх», вы рано или поздно возвращаетесь к исходному элементу: А → Б → В → А. Дерево превращается в граф с циклом, и понятие «уровень вложенности» теряет смысл — уровень становится бесконечным.

Типичный симптом — сообщение платформы «Ошибка при выполнении запроса: зацикливание уровней» или аналогичное при построении запроса с конструкцией ИТОГИ ПО ... ИЕРАРХИЯ, при обращении к виртуальным таблицам с иерархией либо при выводе списка справочника в режиме дерева. В коде, написанном вручную, зацикливание проявляется как переполнение стека из-за бесконечной рекурсии.

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

Откуда берётся зацикливание: типовые причины

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

Вторая частая причина — ручное или пакетное изменение родителя без проверки. Пользователь через групповое изменение реквизитов переносит группу внутрь её собственной подгруппы, а платформа по умолчанию не всегда блокирует такое действие, если в конфигурации не написана проверка в обработчике ПередЗаписью.

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

Ошибка запроса«Зацикливание уровней» при ИТОГИ ПО ... ИЕРАРХИЯ

Проверить, какой справочник участвует в запросе

Зависание отчётаОтчёт по иерархии строится бесконечно долго

Проверить справочники, по которым идёт группировка

Переполнение стекаОшибка в рекурсивной процедуре

Проверить условие выхода из рекурсии и данные

Проблемы обменаЦикл появился после синхронизации

Сравнить родителей элемента в обоих узлах

Как найти зацикленные элементы

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

bsl
Функция НайтиЗацикливание(Ссылка)
	Пройденные = Новый Соответствие;
	Текущий = Ссылка;
	Пока ЗначениеЗаполнено(Текущий) Цикл
		Если Пройденные[Текущий] <> Неопределено Тогда
			Возврат Истина; // цикл найден
		КонецЕсли;
		Пройденные.Вставить(Текущий, Истина);
		Текущий = Текущий.Родитель;
	КонецЦикла;
	Возврат Ложь;
КонецФункции

Альтернатива без кода — запрос с соединением таблицы справочника самой с собой по цепочке родителей. Прямой запрос «элемент = родитель своего родителя» ловит только короткие циклы длиной два-три звена; длинные кольца так не находятся, поэтому обход в коде предпочтительнее. Также полезен простой частный случай: выбрать элементы, у которых Ссылка = Родитель, — самоссылка ловится одним запросом мгновенно.

Порядок поиска цикла
  1. 1
    Сделайте резервную копию базы или работайте на копии
  2. 2
    Найдите элементы с совпадающими Ссылка и Родитель простым запросом
  3. 3
    Запустите обход всех элементов с запоминанием пройденных ссылок
  4. 4
    Зафиксируйте список элементов, входящих в кольцо
  5. 5
    Определите, какой из элементов должен быть корнем или потомком по смыслу учёта

Как исправить зацикливание в данных

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

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

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

Зацикливание в программном коде

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

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

Профилактика: как не допустить повторения

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

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

Типичные ошибки
01
Исправление цикла только в одном узле обмена — после синхронизации кольцо собирается заново
02
Поиск только самоссылок запросом Ссылка = Родитель — длинные циклы через 3–5 элементов остаются незамеченными
03
Рекурсивный обход без соответствия посещённых ссылок — переполнение стека на первом же зацикленном элементе
04
Пакетный перенос групп без проверки вложенности — массовое создание новых циклов вместо исправления старых

Проверка результата и границы самостоятельной работы

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

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

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

Повторный поиск циклов обходом
Норма

Циклы не найдены ни в одном элементе

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

Найдены новые или оставшиеся кольца

Запрос с ИТОГИ ПО ИЕРАРХИЯ
Норма

Выполняется без ошибки зацикливания

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

Ошибка воспроизводится

Отчёт с группировкой по иерархии
Норма

Строится за обычное время

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

Зависает или растёт потребление памяти

Обмен данными после исправления
Норма

Синхронизация проходит, цикл не возвращается

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

После обмена кольцо появляется снова

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

Итог

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

Зацикливание уровней — это кольцо в ссылках «Родитель» иерархического объекта. Находится обходом с запоминанием пройденных ссылок, исправляется разрывом кольца переназначением родителя, предотвращается проверкой в ПередЗаписью и контролем обменов. Любые массовые правки — только после резервной копии.

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

Может ли зацикливание появиться «само», без действий пользователей?

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

Опасно ли зацикливание для остальных данных базы?

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

Почему запрос с ИТОГИ ПО ИЕРАРХИЯ падает, а обычный список открывается нормально?

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

Как найти цикл, если элементов в справочнике сотни тысяч?

Обход в коде с соответствием посещённых ссылок работает быстро даже на больших объёмах, если получать родителей запросом пакетно, а не по одному элементу. Практический приём: сначала выгрузить пары «элемент — родитель» одним запросом в таблицу значений, а затем искать циклы уже в памяти, без обращений к базе.

Нужно ли исправлять цикл в обоих узлах распределённой базы?

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

Можно ли запретить создание циклов на уровне конфигурации?

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