Как программно отключить автоматическое добавление соединений в СхемеЗапроса?

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

При программной работе с конструктором запросов через объект СхемаЗапроса мы часто сталкиваемся с неожиданным поведением платформы: при добавлении новой таблицы (источника) система автоматически создает соединения (JOIN) с другими таблицами. Это может привести к ошибкам вида "Противоречивая связь" или к некорректной выборке данных, если логика автоматического соединения отличается от задуманной разработчиком.

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

Почему появляются лишние соединения?

Как выяснилось в ходе обсуждения и анализа поведения платформы, объект СхемаЗапроса наследует логику визуального Конструктора запроса. Когда мы добавляем таблицу, платформа анализирует метаданные:

  1. Если в новой таблице есть реквизиты, ссылающиеся на уже добавленные таблицы, создается связь.
  2. Если в уже существующих таблицах есть ссылки на новую таблицу, связь также может быть создана.

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

Решение 1: Очистка соединений у нового источника

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

Рассмотрим функцию-обертку, которая позволяет добавлять источник "чистым":


// Функция добавляет источник и опционально очищает его связи
Функция ДобавитьИсточникСхемы(КоллекцияИсточников, ДоступнаяТаблица, Псевдоним, УдалятьАвтоСоединения = Истина) Экспорт
	
	Результат = КоллекцияИсточников.Добавить(ДоступнаяТаблица, Псевдоним);
	
	// Если флаг установлен, удаляем все, что платформа добавила сама
	Если УдалятьАвтоСоединения Тогда
		Результат.Соединения.Очистить();		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

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

Решение 2: Полная зачистка (удаление обратных связей)

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

Чтобы гарантированно избавиться от всех авто-соединений, нам необходимо:

  1. Запомнить количество соединений у всех существующих источников.
  2. Добавить новый источник.
  3. Очистить соединения у нового источника.
  4. Проверить старые источники: если количество соединений выросло, удалить лишние.

Посмотрим, как можно реализовать такой алгоритм:


Процедура ДобавитьИсточникБезЛишнихСвязей(Схема, ПутьКТаблице, Псевдоним)
	
	// 1. Запоминаем текущее состояние соединений у существующих источников
	СостояниеСоединений = Новый Соответствие;
	Для Каждого Источник Из Схема.Источники Цикл
		СостояниеСоединений.Вставить(Источник, Источник.Соединения.Количество());
	КонецЦикла;
	
	// 2. Добавляем новый источник
	НовыйИсточник = Схема.Источники.Добавить(ПутьКТаблице, Псевдоним);
	
	// 3. Очищаем связи самого нового источника
	НовыйИсточник.Соединения.Очистить();
	
	// 4. Проверяем, не появились ли связи у старых источников
	Для Каждого ЭлементСоответствия Из СостояниеСоединений Цикл
		Источник = ЭлементСоответствия.Ключ;
		БылоСоединений = ЭлементСоответствия.Значение;
		
		ТекущееКоличество = Источник.Соединения.Количество();
		
		// Если соединений стало больше, удаляем последние добавленные
		Пока ТекущееКоличество > БылоСоединений Цикл
			// Автоматические связи обычно добавляются в конец коллекции
			Источник.Соединения.Удалить(ТекущееКоличество - 1);
			ТекущееКоличество = ТекущееКоличество - 1;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

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

Альтернативный подход: Инициализация текстом

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

Мы можем сформировать "скелет" запроса в виде текстовой строки (где прописаны только источники без соединений) и загрузить его в схему:


ТекстЗапроса = "ВЫБРАТЬ * ИЗ Справочник.Номенклатура КАК Номенклатура, Справочник.Контрагенты КАК Контрагенты";
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(ТекстЗапроса);

При таком подходе объект СхемаЗапроса распарсит текст и создаст источники, но не будет пытаться "додумывать" соединения, так как в тексте их явно нет. Далее можно продолжать работу с объектом, добавляя поля и условия отбора.

← На главную