Здравствуйте!
Задача: Организовать фильтрацию по вложенным записям в древовидном реестре.
Есть грид, который служит только для отображения записей и дерево с одной степенью вложенности.
Записи вида 00001 - корневые
000001-1, 000001-2, 000001-3 - подчиненные
Также в таблице есть поля с идентификаторами ID, ParentID. Для корневых записей ID = ParentID
В общем, все организовано по примеру раздела [Проекты], но в проектах реализован хитрый механизм фильтрации, который позволяет фильтровать по подчиненным записям, с любой вложенности. Вы можете проверить это профильтровав раздел Проекты, по названию подчиненной стадии, предварительно ее создав.
Я подозреваю, что получилось организовать такую хитрую фильтрацию с помощью следующих механизмов:
ProjectWorkspace.IsChangeFilterScheme = false;
ProjectWorkspace.GridFiltersScheme = new Object();
ProjectWorkspace.GridFiltersScheme.XMLStorage = GetNewXMLStorage();
ProjectWorkspace.GridFiltersScheme.CustomFilters = GetNewXMLStorage();
var GridCustomFilters = ProjectWorkspace.GridFiltersScheme.CustomFilters;
GridCustomFilters.InitRootNode('CustomFilters');
GridCustomFilters.RootNode.AddChildNode('FiltersData');
SaveFiltersToScheme(ProjectWorkspace.GridFiltersScheme);
ProjectWorkspace.GanttFiltersScheme = new Object();
ProjectWorkspace.GanttFiltersScheme.XMLStorage = GetNewXMLStorage();
ProjectWorkspace.GanttFiltersScheme.CustomFilters = GetNewXMLStorage();
var GanttCustomFilters = ProjectWorkspace.GanttFiltersScheme.CustomFilters;
GanttCustomFilters.InitRootNode('CustomFilters');
GanttCustomFilters.RootNode.AddChildNode('FiltersData');
SaveFiltersToScheme(ProjectWorkspace.GanttFiltersScheme);
}
function SaveFiltersToScheme(Scheme) {
var CustomFiltersNode = Scheme.CustomFilters.RootNode.Items(0);
CustomFiltersNode.SetAttributeAsBool('ShowForPeriod', chbShowForPeriod.IsChecked, false);
SetStrAttributeToXMLNode(CustomFiltersNode, 'PeriodType', cbPeriodType.DataField.Value);
SetStrAttributeToXMLNode(CustomFiltersNode, 'FromDate', dtcFromDate.DataField.Value);
SetStrAttributeToXMLNode(CustomFiltersNode, 'ToDate', dtcToDate.DataField.Value);
CustomFiltersNode.SetAttributeAsBool('ShowForOpportunity', chbShowForOpportunity.IsChecked, false);
SetStrAttributeToXMLNode(CustomFiltersNode, 'Project', edtProject.Value);
CustomFiltersNode.SetAttributeAsBool('ShowForContact', chbShowForContact.IsChecked, false);
SetStrAttributeToXMLNode(CustomFiltersNode, 'Contact', edtContact.Value);
CustomFiltersNode.SetAttributeAsBool('ShowChildren', chbShowChildren.IsChecked, false);
Scheme.FilterBuilder = GetFilterBuilderXMLDataEx(fbcFilters, Scheme.XMLStorage);
}
function LoadFiltersFromScheme(Scheme) {
var CustomFiltersNode = Scheme.CustomFilters.RootNode.Items(0);
chbShowForPeriod.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForPeriod', false);
var DateEnumID = GetStrAttributeFromXMLNode(CustomFiltersNode, 'PeriodType');
if (IsEmptyValue(DateEnumID)) {
dtcFromDate.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'FromDate');
dtcToDate.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'ToDate');
} else {
cbPeriodType.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'PeriodType');
}
chbShowForOpportunity.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForOpportunity', false);
edtProject.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'Project');
chbShowForContact.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForContact', false);
edtContact.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'Contact');
chbShowChildren.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowChildren', false);
fbcFilters.ClearFilter();
fbcFilters.FiltersBuilder.Deserialize(Scheme.FilterBuilder);
fbcFilters.Refresh();
fbcFilters.ApplyFilter();
}
Я так понимаю, что мы должны научить FilterBuilder ходить по вложенным записям, для этого переопределить логику, но как это делается в строчках выше мне не понятно.
Просьба пояснить или дать пример организации корректной фильтрации по древовидному реестру.
Конфигурация Terrasoft 3.3.2.157
Бинарные файлы Terrasoft 3.3.2.268
Нравится
Здравствуйте.
Уточните, пожалуйста, при фильтрации Вам необходимо чтобы отображалась только(!) подчиненная запись и её родитель, или же родитель этой записи и все подчиненные этому родителю записи?
Здравствуйте Дмитрий,
Необходимо отображать:
"Олейник Дмитрий" написал:родитель этой записи и все подчиненные этому родителю записи
Здравствуйте.
Предлагаю базовый механизм быстрого фильтра не трогать, а добавить какую либо кнопку "Фильтр" в окно древовидного реестра.
На OnClick пропишем примерно следующее:
var Dataset = dlData.Dataset; Dataset.DisableEvents(); vat FilterText = edtFilterText.Value; ApplyDatasetFilter(Dataset, 'Text', FilterText, true); Dataset.Open(); var ParentID = Dataset('ParentID'); if(ParentID != null) { Dataset.Close(); EnableAllFilters(Dataset.SelectQuery.Items(0).Filters, false); ApplyDatasetFilter(Dataset, 'ID', ParentID, true); Dataset.Open(); } RefreshDataset(Dataset); Dataset.EnableEvents();
Здравствуйте Дмитрий,
Спасибо за идею с обходным решением, не проверял его еще на практике.
Но так как есть требование иметь полную функциональность работы с фильтрами (как в разделе проекты) у меня есть более "красивая" идея как реализовать задачу.
По сути когда мы ставим Like фильтр по какому либо из полей (допустим текстовом) в древовидном реестре, Террасофт посылает запрос
... WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%'')) ...
где @P1 значение введенное в клиенте
И данные запрос нам вернет ID подчинённых записей, но не корневых. Так как корневых записей нет, в гриде мы ничего не увидим.
Обыграть это можно построив запрос вида:
select tbl_ControlPaySection.OffshNumber from tbl_ControlPaySection where tbl_ControlPaySection.name like '% текст %' or ID in (select ParentID from tbl_ControlPaySection a where a.name like '% текст %' ) order by tbl_ControlPaySection.OffshNumber
Для того что бы в TSAdmin'е делать подобные фильтры, есть функциональность Пользовательских фильтров (User Filter). Построить подобный запрос можно следующим образом (В данном случае у нас будет String User Filter):
Проблема в том, что когда вызвать этот Пользовательский фильтр в клиенте, Террасофт сформирует запрос:
... WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%'')) ORDER BY 5 ASC',N'@P1 nvarchar(4000)',N'текст с клиента'
т.е он не учитывает логики которая прописана в TSAdmin а просто делает Like по полю, как будто пользовательского фильтра нет.
Если пользовательский фильтр активировать (поставить галочку) ситуация не поменяется.
Конфигурация Terrasoft 3.3.2.157
Бинарные файлы Terrasoft 3.3.2.268
Здравствуйте!
А если включить корневой блок WHERE?
Для полноценной фильтрации (по аналогии с разделом "Проэкты"), после ApplyDatasetFilter по искомому поисковому запросу, Вам необходимо проверить, корневой это узел или нет. В случае если ParentID <> null, необходимо фильтровать датасет по этому ParentID, в ином случае (ParentID = null) фильтрация пройдет корректно.
"Олейник Дмитрий" написал:А если включить корневой блок WHERE?
Ситуация не поменялась
"Олейник Дмитрий" написал:Для полноценной фильтрации (по аналогии с разделом "Проэкты"), после ApplyDatasetFilter по искомому поисковому запросу, Вам необходимо проверить, корневой это узел или нет. В случае если ParentID <> null, необходимо фильтровать датасет по этому ParentID, в ином случае (ParentID = null) фильтрация пройдет корректно.
Данный комментарий к коду
"Олейник Дмитрий" написал:var Dataset = dlData.Dataset;
Dataset.DisableEvents();
vat FilterText = edtFilterText.Value;
ApplyDatasetFilter(Dataset, 'Text', FilterText, true);
Dataset.Open();
var ParentID = Dataset('ParentID');
if(ParentID != null)
{
Dataset.Close();
EnableAllFilters(Dataset.SelectQuery.Items(0).Filters, false);
ApplyDatasetFilter(Dataset, 'ID', ParentID, true);
Dataset.Open();
}
RefreshDataset(Dataset);
Dataset.EnableEvents();
понятен, но как сделать что бы можно было пользоваться FilterBuilder'ом?
Просьба уточнить, как работают пользовательские фильтры (User Filter), в случае строкового фильтра (String User Filter).
Что я делаю не так в пользовательском запросе что он формирует запрос к БД
LEFT OUTER JOIN [dbo].[tbl_OffshClients] AS [tbl_OffshClients] ON [tbl_OffshClients].[ID] = [tbl_OffshCompanys].[Clients] WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%'')) ORDER BY 4 DESC',N'@P1 nvarchar(4000)',N'Годовой'
и не учитывает всю логику подзапросов.
Дмитрий, постройте простой SQ с пользовательским фильтром с логикой отчличной от Like фильтрации по полю табл., и вы поймете, срабатывают в принципе пользовательские фильтры. Как я вижу не срабатывают, а должны.
Здравствуйте.
"АльфаКрыса" написал: но как сделать что бы можно было пользоваться FilterBuilder'ом?
Для того чтобы пользоваться Filter Build'ером, необходимо в sq добавить Union таблицы саму на себя, после чего добавить фильтр NotExistInChild, ExistsInPath по аналогии c sq_Project.