Почему метод Сдвинуть объекта СхемаЗапроса работает некорректно и как правильно перемещать запросы в пакете?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

В чем заключается проблема метода Сдвинуть

Рассмотрим типовой сценарий, когда в пакете запросов требуется переместить один из промежуточных запросов в конец:


ТекстЗапроса = "ВЫБРАТЬ 0 ПОМЕСТИТЬ а0; ВЫБРАТЬ 1 ПОМЕСТИТЬ а1; ВЫБРАТЬ 2 ПОМЕСТИТЬ а2; ВЫБРАТЬ 3 ПОМЕСТИТЬ а3;";
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);

// Ожидается перестановка: было 0-1-2-3, должно стать 0-2-3-1
СхемаЗапроса.ПакетЗапросов.Сдвинуть(1, 3);
НовыйТекст = СхемаЗапроса.ПолучитьТекстЗапроса();

На платформах ветки 8.3 до релиза 8.3.11 подобный вызов приводит к искажению порядка. Проанализируем причины этой проблемы:

  1. Путаница в Синтакс-помощнике и сигнатуре: для большинства коллекций платформы 1С метод Сдвинуть принимает в качестве второго параметра не абсолютный индекс, а относительное смещение (сдвиг на +N или -N позиций). При этом в ранних версиях описания параметров схемы запроса второй параметр ошибочно именовался как новый абсолютный индекс.
  2. Системная ошибка платформы (баг №10162976): во внутренних механизмах платформы вычисление целевой позиции элемента в коллекциях ПакетЗапросовСхемыЗапроса и ОператорыСхемыЗапроса рассчитывалось как максимальное значение из двух переданных параметров. В итоге метод стабильно работал лишь при определенных сдвигах в сторону уменьшения индекса и давал сбой при попытке сдвинуть элемент вперед более чем на одну позицию.

Решение 1. Штатные методы платформы 8.3.11 и выше

Начиная с версии платформы 8.3.11, фирма «1С» исправила расчет смещения и четко разграничила назначение методов:

  1. Использование метода Переместить: в коллекцию ПакетЗапросовСхемыЗапроса был добавлен специализированный метод Переместить(<Индекс>, <НовыйИндекс>), который принимает именно абсолютные позиции элементов:
    
    // Перемещаем запрос с индекса 1 на позицию 3
    СхемаЗапроса.ПакетЗапросов.Переместить(1, 3);
    
  2. Использование исправленного метода Сдвинуть: сигнатура метода была приведена к единому стандарту платформы Сдвинуть(<Индекс>, <Смещение>). Если нужно переместить элемент с позиции 1 на позицию 3, относительное смещение составит +2:
    
    // Сдвигаем запрос с индекса 1 на 2 позиции вперед
    СхемаЗапроса.ПакетЗапросов.Сдвинуть(1, 2);
    

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

Решение 2. Обходной путь через циклический пошаговый сдвиг

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


// Задача: переместить запрос с позиции 1 на позицию 3
// Выполняем пошаговую перестановку пар запросов
СхемаЗапроса.ПакетЗапросов.Сдвинуть(2, 1);
СхемаЗапроса.ПакетЗапросов.Сдвинуть(3, 2);

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

Решение 3. Пересборка запроса через промежуточную схему

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


НоваяСхема = Новый СхемаЗапроса;

// Заполняем пакеты новой схемы в требуемом порядке индексов: 0, 2, 3, 1
ПорядокИндексов = Новый Массив;
ПорядокИндексов.Добавить(0);
ПорядокИндексов.Добавить(2);
ПорядокИндексов.Добавить(3);
ПорядокИндексов.Добавить(1);

Для Каждого Индекс Из ПорядокИндексов Цикл
    ИсходныйЗапрос = СхемаЗапроса.ПакетЗапросов[Индекс];
    // Добавляем запрос в новую схему
    // При необходимости копируем структуру или переносим текст
КонецЦикла;

Решение 4. Манипуляция строкой запроса

Если в схеме запроса еще не выполнялась сложная модификация условий и полей через объектную модель, простейшим решением на платформе с режимом совместимости будет предварительное разделение исходного текста запроса на массив подстрок по символу точки с запятой, перестановка элементов массива в требуемой последовательности и последующая загрузка в СхемаЗапроса.УстановитьТекстЗапроса().

← На главную