Есть задача сделать предварительную фильтрацию для LookUpControl'а с MultiSelectWindow. Смысл в том чтоб получить список сотрудников, которые являются инициаторами(owner) по задачам. Подсмотрел подобную технологию в скрипте wnd_ReportFinanceResultScript(причем на датасете, который я использую для фильтрации списка пользователей отобранных в MultiSelectWindow такое включение фильтра IN работет). Написал собственный фильтр OwnerID(см.рисунок) в датасете ds_Contact(для фильтра типа Exists с кодом DocumentFilters) На событии OnPrepareSelectWindow окна пишу код:

var Dataset = dlContact.Dataset;//ds_Contact
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; - нулл или не является объектом
попытке обратиться прямо к фильтру в строке:
Filters('DocumentFilters').IsEnabled = true;

та же ошибка...
пробовал
Dataset.SelectQuery.Items(0).Filters.ItemByCode('DocumentFilters').IsEnabled = true;

тоже ошибка.
Попробовал включить в сервисе qs_Contact в фильтре DocumentFilters явно свой фильтр OwnerID и наложить функцией
EnableDatasetFilters(Dataset, true, 'DocumentFilters');
ошибки нет, НО фильтр не срабатывает.
Остановился на фильтрации списка по сотрудникам предприятия функцией

Нравится

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

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

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