Добавление фильтра NotExists не связанного с корневой схемой

Добрый день.

 

Подскажите - каким образом можно сформировать часть клиентского фильтра типа NotExists на выборку, никак не связанную с корневой схемой, фильтрацию которой мы осуществляем?

Пример: Есть контакты, у них есть некий тип. И есть объект, скажем, "Разрешенные типы контактов". Нужно сделать выбор контактов по следующему условию: тип контакта присутствует в разрешенных (это легко), если разрешенные типы заполнены. Если не заполнены, то разрешен любой тип (вот это не понимаю как добавить в условие) 

Технически мне нужен фильтр на сущность Contact вида

Contact.Type in (AllowedTypes.Id) OR (NOT EXISTS (select * from AllowedTypes))

Проблема в том, что в куске после OR требуется фильтр, никак не связанный с Contact, а построитель путей к колонкам автоматически привязывает всё к корневой схеме.

Нравится

8 комментариев

Добрый день.

 

Вы можете реализовать проверку на заполненность таблицы "Разрешенные типы контактов" простым селектом к этой таблице.

 

А потом уже в зависимости от этого условия через if реализовать фильтрацию. Если в разрешенных типах есть записи, то включать первый фильтр тип контакта присутствует в разрешенных, если нет, то отключать.

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

 

Виталий, а Вы случайно не стандартный механизм деактивации записи в справочнике изобрести пытаетесь?

Если одно или несколько значений справочника устарели и больше не используются, то такие значения можно деактивировать. Деактивированное значение не будет отображаться при выборе значений в справочных полях. При этом пользователи продолжат видеть это значение в тех записях, где оно было указано ранее, и смогут использовать его для фильтрации. По умолчанию возможность деактивировать значения справочника выключена. Разрешить деактивацию записей для нужного справочника можно в разделе [Конфигурация]. Подробнее о настройке читайте в статье “Деактивация записей объектов”.

 

Деактивированное значение справочника [Типы статей базы знаний]

section_lookups_deactivated_record_example.png

 

Коллеги, спасибо за ответы.

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

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

Все настройки фильтров в клиентском коде в итоге всё равно превращаются в запросы к DataService. О фильтрах в ней есть тут и не уверен, что получится такое, как Вы хотите. Сложный exists делают тут, но всё равно со связью с основной таблицей.

 

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

 

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

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

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

 

Уверенна, дорогу осилит идущий...

О, в этой теме ещё через view не предлагали.

Зверев Александр,

Кстати, да, как вариант laugh

Итак, я всё-таки решил эту интересную головоломку, оставлю ответ тут на случай если кто-то ещё столкнется с подобным.
Подсказку для начала решения нашел вот здесь - это помогло вспомнить, что для subfilter путь к колонке указывается относительно подсхемы вышестоящего фильтра, а не root-схемы всего запроса, то что нужно.
Однако, получается, что всё равно невозможно составить запрос именно в том виде, что я описал изначально, т.к. вышестоящий фильтр всё же должен быть как-то связан с root-схемой. Поэтому здесь мне пришлось немножко одурачить esq и подсунуть связь там, где её на самом деле нет. Это можно сделать с помощью двух вложенных  фильтров - notexists внутри exists, причем внешний exists должен иметь связь с root схемой и быть true всегда. Например, exists (наш статус в справочнике статусов)
Таким образом, изначальный запрос 

select * from Contact where Contact.StateId = @someState
or not exists (select Id from AllowedStates) /* вот эту часть в чистом виде записать на esq нельзя, нет связи с Contact*/

превращается в

select * from Contact where Contact.StateId = @someState 
or exists (select Id from State where State.Id = Contact.StateId /*вот она нужная связь*/ and not exists (select StateId from AllowedStates)) /* true только тогда, когда true нужный нам notexists.*/

или на js это выглядит примерно так (root-схема Contact, код не проверял, т.к. в оригинале объекты совсем другие и связи запутаннее)

var allowedStateFilterGroup = Ext.create("Terrasoft.FilterGroup");
allowedStateFilterGroup.logicalOperation = this.Terrasoft.LogicalOperatorType.OR;
var stateFilter = Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
	"State", someState);	
var notExistsStateFilter = Terrasoft.createExistsFilter("[State:Id:State].Id");
notExistsStateFilter.subFilters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Id", someState));
notExistsStateFilter.subFilters.addItem(Terrasoft.createNotExistsFilter("[AllowedStates:State].Id"));
allowedStateFilterGroup.add("StateFilter", stateFilter);
allowedStateFilterGroup.add("NotExistsStateFilter", notExistsStateFilter);

Esq вообще удивительно гибкая штука, стоит только заглянуть чуть глубже привычного createColumnFilterWithParameter.
Как я предполагал, всё что нужно делается прямо внутри функции filters, не нужны тут никакие view, ужас какой, не путайте людей.

Показать все комментарии