Добрый день.
Очень радует то, что хорошо известная библиотека ЕhLib сейчас более-менее активно развивается и поддерживается автором и хочется помочь своими "пятью копейками" в ее развитии.
Я использую связку
TIBXDataDriver + TMemTableEh + TDBGridEh. Версия EhLib 4.4.48
Я попытался использовать серверную фильтрацию и сортировку, и если я правильно понял, то в текущей версии пока ее можно использовать только для простейших случаев для полей из основной таблицы. Для вычисляемых в select полей, полей на основе вложенных подзапросов, полей с алиасами т.д. в текущем виде серверная сортировка работать как я понял не будет?
С серверной сортировкой проблем гораздо меньше чем с фильтрацией, т.к. можно использовать порядковые номера столбцов в конструкции ORDER BY. Для выполнения серверной фильтрации нужно знать не только имя столбца в результате SQL запроса, а и само SQL выражение которое сформировало столбец.
В коде функции GetExpressionAsFilterString в файле DbUtilsEh при построении выражения для серверной фильтрации используется или имя поля или свойство Origin, если оно заданно, но судя по справке это свойство обычно пустое.
Help |
The Origin property is only implemented for BDE-enabled datasets, which appear only in the Windows product. |
Не знаю как при работе через ADO или FIB'ы, но по крайней мере при работе через IBX у меня всегда так.
Что бы решить задачу построения правильного SQL выражения для сортировки на сервере для произвольных полей я набросал на основе своего старого кода функцию, которая парсит Select SQL, вычленяя выражения для формирования полей, сопоставляет их с TField в DataSet и записывает в соответствующие TField датасета в свойство Orign выражение из SQL запроса, формирующее это поле. При разборе учитываются однострочные и многострочные комментарии, алиасы указанные через пробел или через AS, кавычки в именах полей, алиасов, строковые константы и т.д.
Таким образом появляется возможность корректно строить запросы на фильтрацию практически для любых по сложности полей, в том числе с арифметическими или строковыми операциями, функциями, с полями на основе вложенных подзапросов и т.д.
Проблемными являются запросы с использованием UNION, т.к. в этом случае думаю что невозможно сформировать условие сортировки на сервере - только на клиенте и запросы типа select таблица1.*, (вложенный подзапрос без явного алиаса), таблица2.* from ..., т.к. здесь проблематично сопоставить поля SQL запроса с полученными полями в DataSet.
Также нюансом является то, что если поля в DataSet создаются динамически, то присвоенные значения Orign теряются после переоткрытия.
Модуль uEhMyUtils.pas выкладываю у себя по адресу:
http://www.plaincad.com/EhLiBВ этой же папке проект для UnitTest работы модуля.
Эти модули можно свободно использовать, распространять и редактировать. Идеально было бы всем миром его протестировать, подоптимизировать и в идеале, возможно, включить в ehlib.
Алгоритм использования:
1. Сделать Open для TMemTableEh.
2. Вызвать SetFieldOrigin(lMemTable, MainSQL);
Где MainSQL по сути тот Select SQL из связанного объекта SQLDatadriver.
3. Все... Теперь серверная фильтрация и сортировка должна работать (при условии исправления функции procedure TMTEDatasetFeaturesEh.ApplyFilter(Sender: TObject; DataSet: TDataSet; IsReopen: Boolean) как описано ниже).
Замечания:
1. Проверенно, работает для вычисляемых полей, полей на основе вложенных подзапросов и т.д. Я использую связку
TIBXDataDriver + TMemTableEh + TDBGridEh3. Для правильной работы серверной фильтрации никто не отменял наличие строки
whrere
/*Filter*/ (1=1)
в Select запросе в TIBXDataDriver;
и подключенного в uses модуля EhLibMTE
4. В функции TMTEDatasetFeaturesEh.ApplyFilter модуля EhLibMTE.pas (Build 4.4.05) нужно обязательно заменить строки начиная с
end else if (DataDriver is TSQLDataDriverEh) then
(у меня это строка № 500), на
end else if (DataDriver is TBaseSQLDataDriverEh) then
begin
ApplyFilterForSQLDataDriver(TCustomDBGridEh(Sender),
TSQLDataDriverEh(DataDriver), DateValueToSQLString);
DataSet.Close;
DataSet.Open;
end;
end;
В ранних версиях модуля EhLibMTE.pas (до (Build 4.4.05) )нужно подобную замену сделать и для функции TMTEDatasetFeaturesEh.ApplySorting
5. После однократного применения фильтра или сортировки - все перестает работать. Да есть такая багофича связана с тем что после переоткрытия MemTable, значения Origin теряются так как Fileds пересоздается. Вариантов решения проблемы вижу два
1. Вызывать SetFieldOrigin(lMemTable, MainSQL) на событии AfterOpen для lMemTable
2. Запретить удалять столбы при переокрытии lMemTable.
Напрямую как сделать это не нашел. Использовал след. код после первого открытия MemTable:
type
_TCrackTDataSet = class(TDataSet);
...
_TCrackTDataSet(lMemTable).SetDefaultFields(false);
Вроде как все.
Если мои выкладки верны и я ничего глобального не упустил из виду, то модуль может быть полезен многим. Буду рад, если пригодится.
Жду замечаний. Может эту задачу можно решить как-то по другому, интересно узнать.
--
Vladislav Matvienko
http://www.PlainCAD.com -
графический редактор для создания схем