Включение фильтра типа Exists.Достучаться до фильтров в Подзапросе :-)
Есть задача сделать предварительную фильтрацию для LookUpControl'а с MultiSelectWindow. Смысл в том чтоб получить список сотрудников, которые являются инициаторами(owner) по задачам. Подсмотрел подобную технологию в скрипте wnd_ReportFinanceResultScript(причем на датасете, который я использую для фильтрации списка пользователей отобранных в MultiSelectWindow такое включение фильтра IN работет). Написал собственный фильтр OwnerID(см.рисунок) в датасете ds_Contact(для фильтра типа Exists с кодом DocumentFilters) На событии OnPrepareSelectWindow окна пишу код:
var OurOrgn = 'E4FCB451-2010-49E7-8B8A-05AE2E350B9F';
//Получение коллекции фильтров запроса датасета(в данном случае ds_Contacts)
var Filters = Dataset.SelectQuery.Items(0).Filters;
//Получение коллекции фильтров для фильтра типа Exists в запросе датасета
var FiltersContacts =
Filters('DocumentFilters').TestExpression.ExpressionSelectQuery.Items(0).Filters;
// Фильтр по контактам собственного предприятия
// ApplyDatasetFilter(Dataset, 'AccountID', OurOrgn, true);
Dataset.FetchRecordsCount = -1;
// Включение фильтра по имени
Filters('DocumentFilters').IsEnabled = true;
//Отключение фильтра в запросе Exists, который включен по умолчанию
FiltersContacts('DocumentContactID').IsEnabled = false;
//Подключение фильра по "владельцу" задачи
FiltersContacts('OwnerID').IsEnabled = true;
//EnableDatasetFilters(Dataset, true, 'DocumentFilters');
//Dataset.SelectQuery.Items(0).Filters.ItemByCode('DocumentFilters').IsEnabled = true;
//var SelectQuery = Dataset.SelectQuery;
//EnableSelectQueryFilters(SelectQuery, true,'DocumentFilters');
SetControlAttribute(LookupControl, SelectWindow);
Результат - ошибка отладчик показывает строку var FiltersContacts =
Filters('DocumentFilters').TestExpression.ExpressionSelectQuery.Items(0).Filters; - нулл или не является объектом
попытке обратиться прямо к фильтру в строке:
та же ошибка...
пробовал
тоже ошибка.
Попробовал включить в сервисе qs_Contact в фильтре DocumentFilters явно свой фильтр OwnerID и наложить функцией
EnableDatasetFilters(Dataset, true, 'DocumentFilters');
ошибки нет, НО фильтр не срабатывает.
Остановился на фильтрации списка по сотрудникам предприятия функцией
Нравится
ApplyDatasetFilter(Dataset, 'AccountID', OurOrgn, true);
Как вариант подходит, но хочется с проблемой разобраться...Помогите, кто чем может...мы сами не местные(с) :-)
Хм.. а попробуйте в дебагере найти свой фильтр путем просмотра
Filters.Items(n)
Такое впечатление, что просто неправильно написанное имя фильтра, хотя со скрином вроде как сходится ..
Для включения compare фильтра используйте ApplydatasetFilter(датасет, название_фильтра, значение, true)
При этом название_фильтра должно обязательно совпадать с названием параметра в запросе.
Для включения exist Вы можете передать параметры Dataset.SelectQuery.Parameters('...').Value = ...; а затем включить его через EnableSelectQueryFilters(Dataset.SelectQuery, true,'...')
Спасибо,Доленко Юрий, научил "....как ходють, как сдают..."(с) а теперь знатокам ВОПРОС
В дебаггере, я получил следующую информацию:
Dataset.USI
"Contacts\General\Main Grid\ds_Contact"
Filters.Count
13
Filters.Items(12).Code
"TeamProjectID"
Filters.Items(14).Code
List index out of bounds (14)
Ну и кто мне скажет ПОЧЕМУ??????
Если в коллекции фильтров запроса sq_Contact визуально их штук 20?
"Стоян Виталий" написал:Для включения compare фильтра используйте ApplydatasetFilter(датасет, название_фильтра, значение, true)
При этом название_фильтра должно обязательно совпадать с названием параметра в запросе.
Наверное название_фильтра совпадать не с названием и не с параметра, а все таки с КОДОМ фильтра в коллекции...
Подобный фильтр я в итоге и использовал, это написано во-втором посте... изначально задача была другой
"Черных Руслан" написал:Смысл в том чтоб получить список сотрудников, которые являются инициаторами(owner) по задачам
"Стоян Виталий" написал:
Для включения exist Вы можете передать параметры Dataset.SelectQuery.Parameters('...').Value = ...; а затем включить его через EnableSelectQueryFilters(Dataset.SelectQuery, true,'...')
А теперь с этого места подробнее, какие параметры я должен использовать для передачи в exists фильтр DocumentFilters в сервисе sq_Contact(рисунок см. выше)?
Как я понимаю я должен
1. Включить этот фильтр
2. Выключить фильтр DocumentContactID в запросе фильтра DocumentFilters
3. Включить собственно написанный фильтр OwnerID в запросе фильтра DocumentFilters.
И все это у меня не получается по тому, что попытка обратиться к коллекции глубже 13(12, если считать с 0 ) приводит к недоумению системы. :-(
Рекомендации на основании своих опытов с фильтрами в SelectQuery:
1) давайте своим фильтрам уникальные коды. В противном случае при включении их через функции типа ApplyDatasetFilter высока вероятность, что включится совсем другой фильтр (эти функции обрабатывают дерево фильтров рекурсивно и включает первый найденный с требуемым кодом. Мне кажется в sq_Contact есть уже фильтр с кодом OwnerID);
2) судя по скриншоту, новый фильтр OwnerID добавлен в Exists фильтр с пользовательскими фильтрами DocumentDate и DocumentState (извиняюсь за столь частое употребление слова "фильтр", по-другому сложно объяснить :) ). Программное включение такого фильтра, по-моему, не сработает - надо сделать свой фильтр, в котором не будет пользовательских;
3) иерархия фильтров в SelectQuery имеет свойство динамически меняться во время работы Террасофт :). Я не исследовал детально причины, но, к примеру, если пользователь, находясь в разделе Контакты, установит в гриде быстрый фильтр по полю ФИО, то в ds_Contact.SelectQuery.Filters структура фильтров несколько меняется :). Поэтому ориентироваться на положение фильтра в иерархии не стоит, обращение типа Filters.ItemsByCode('...') может не сработать, так как в определенный момент времени правильным может оказаться обращение Filters.Items(0).ItemsByCode('...') :)
Валерий правильно подсказал - прежде всего во избежание проблем нужно название фильтра сделать уникальным
Возможно Ваша проблема решится таким образом (не проверял, написал примерно):
var ExistsFilter = Dataset.SelectQuery.Items(0).Filters.ItemsByCode(Exists_Filter_Code); var YourFilter = ExistsFilter.TestExpression.ExpressionSelectQuery. Items(0).Filters.ItemsByCode(Your_Filter_Code); YourFilter.IsEnabled = true;
Валер, МНЕ не нужен был свой фильтр, я хотел использовать, тот который есть в системе.... то что я создал свой фильтр в подзапросе, который реализует Exists, то обращаясь внутрь этого фильтра там структура имен УНИКАЛЬНА, то что на верхнем уровне в самом запросе может быть такой фильтр, так я ж там его не вызываю, вызов идет уже к фильтру подзапроса - переменная FiltersContacts? Есть человек на форуме со столь глубокими знаниями, который мне объяснит, почему свойство Filters.Count = 13? При вызове датасета из формы окна с LookUpControl? Я проверял до 12 фильтра их порядок соответствует визуальному дереву в конструкторе запроса qs_Contact.
"Валерий Андрусик" написал:Поэтому ориентироваться на положение фильтра в иерархии не стоит, обращение типа Filters.ItemsByCode('...') может не сработать, так как в определенный момент времени правильным может оказаться обращение Filters.Items(0).ItemsByCode('...')
А на что тогда ориентироваться, SDK то же в топку? :-) только собственный опыт и ручная трассировка вызова функций? Шаг в право, шаг влево приводят к непредсказуемым результатам :-)
"Стоян Виталий" написал:Валерий правильно подсказал - прежде всего во избежание проблем нужно название фильтра сделать уникальным
1. Так что пользоваться фильтрами созданными разработчиками Террасофт строго запрещено? :-) Это их ноу-хау и авторские права? Ну давайте все при малейшей необходимости будем "загаживать" датасет своими фильтрами? Как решить эту проблему, чтоб и рыбку, съесть и ... не замочиться я уже сделал, для тех кто "...в танке..."(с) Этот вопрос закрыт!!!!!!!!!!!
Объясните мне поведение датасета при получении коллекции фильтров, которое я описал выше!
2. Виталий ваш код подразумевает добавление фильтра в сервис запроса по -умолчанию в конец списка, а ниже 12 фильтра система их не видит, я (примерно, не проверял) скажу что вызов по коду этого фильтра так же закончиться ошибкой - Требуется объект...
"Черных Руслан" написал:Объясните мне поведение датасета при получении коллекции фильтров, которое я описал выше!
По-моему невключенные в редакторе сервиса запроса пользовательские фильтры не считаются, ну это так на вскидку.
Включите все пользовательские фильтры в редакторе и идите в дебагер еще раз ;)
Я этому безумно рад :-), а как тогда его включить перед использованием программно? Ведь свойство-то IsEnabled никто не отменял?Ведь не может же быть что такая куча фильтров создана и отключена просто так для отладки, их как-то включают?
Насколько я понимаю, пользовательские фильтры идут через FiltersBuilder и там уже на них ядром кастуется какой-то баф, который дает типа "Включение фильтра" +3.
Хотя... вот сейчас нет возможности посмотреть в Террасофт, но вроде моя визуальная память подсказывает мне, что в базовых скриптах есть слова: ApplyUserFilters или как-то так, а может и нет )
Отписался в службу поддержки всем кому интересно - на данный момент есть проблема:
При получении любого фильтра (не только DocumentFilters), в составе которого есть пользовательский фильтр, получаем null.
Данная проблема была передана в отдел разработки для ее решения на уровне ядра системы. Проблема в ядре, изменения запланированы на конец апреля.
Руслан, добрый день.
В процессе анализа Вашего вопроса я пришёл к следующим выводам. Вносить изменения в ядро не нужно. С другой стороны,
"Доленко Юрий" написал:моя визуальная память подсказывает мне, что в базовых скриптах есть слова: ApplyUserFilters или как-то так
Юрий прав. По умолчанию пользовательские фильтры в запросе отключены, так как применять их в скриптах достаточно сложно (и в подавляющем большинстве случаев не нужно, для этого есть менеджер фильтрации). Для доступа к ним в скрипте не поможет простое включение фильтра в запросе, как рекомендовал Юрий.
Решение - необходимо сначала вызвать метод запроса LoadUserFilters(). После этого Вы сможете получить по коду любой фильтр запроса, включая пользовательский. Если, как в Вашем случае, необходимо отключить один фильтр в группе и включить другой, сначала включаем всю группу фильтров, а потом отключаем в ней все ненужные фильтры.
Таким образом, для решения задачи Ваш код необходимо привести к виду:
var Dataset = dlContact.Dataset; var OurOrgn = '{E4FCB451-2010-49E7-8B8A-05AE2E350B9F}'; //Получение коллекции фильтров запроса датасета(в данном случае ds_Contacts) Dataset.SelectQuery.LoadUserFilters(); var Filters = Dataset.SelectQuery.Items(0).Filters; //Получение коллекции фильтров для фильтра типа Exists в запросе датасета var FiltersContacts = Filters.ItemsByCode('DocumentFilters').TestExpression.ExpressionSelectQuery.Items(0).Filters; // Фильтр по контактам собственного предприятия ApplyDatasetFilter(Dataset, 'AccountID', OurOrgn, true); Dataset.FetchRecordsCount = -1; //Отключение фильтра в запросе Exists, который включен по умолчанию Filters.ItemsByCode('DocumentFilters').IsEnabled = true; FiltersContacts('DocumentContactID').IsEnabled = false; FiltersContacts('DocumentDate').IsEnabled = false; FiltersContacts('DocumentState').IsEnabled = false; //Подключение фильра по "владельцу" задачи FiltersContacts('OwnerID').IsEnabled = true; Dataset.Open(); SetControlAttribute(LookupControl, SelectWindow);
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
Спасибо, огромное, Олег Ваша консультация, как всегда в точку. Персональная благодарность.:twisted:
Продолжение обсуждения в теме http://www.community.terrasoft.ua/forum/topic/7265