ЕhLib и серверная фильтрация и сортировка

Vladislav Matvienko
Дата: 07.06.2009 02:44:34
Добрый день.

Очень радует то, что хорошо известная библиотека Е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 + TDBGridEh

3. Для правильной работы серверной фильтрации никто не отменял наличие строки
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 - графический редактор для создания схем
Гаджимурадов Рустам
Дата: 07.06.2009 03:16:48

Vladislav Matvienko
Я использую связку TIBXDataDriver + TMemTableEh + TDBGridEh.

А для чего именно понадобилась такая длинная цепочка?

Vladislav Matvienko
Для вычисляемых в select полей, полей на основе вложенных подзапросов, полей с алиасами т.д. в текущем
виде серверная сортировка работать как я понял не будет?

Имелась в виду фильтрация, наверное ?
Это зависит только от "умности" фильтр-адаптера.

Vladislav Matvienko
Origin ... судя по справке это свойство обычно пустое.
.... при работе через IBX у меня всегда так

Нет. IBTable, небось, юзаешь? :)

Vladislav Matvienko
Модуль uEhMyUtils.pas выкладываю у себя по адресу:
http://www.plaincad.com/EhLiB

Если оттестировал и оно того стоит - лучше пошли
Большакову, пусть выложит в стандартной поставке.
Заодно бета-тестеры смогут проверить.
Ну и мы поможем чем можем, потестим.

А в целом - спасибо.

Posted via ActualForum NNTP Server 1.4

Vladislav Matvienko
Дата: 07.06.2009 13:26:09
Добрый день.

Гаджимурадов Рустам

Vladislav Matvienko
Я использую связку TIBXDataDriver + TMemTableEh + TDBGridEh.

А для чего именно понадобилась такая длинная цепочка?

TMemTableEh для того что получить возможность при необходимости клиентской фильтрации и сортировки, ViewScrool, и важно было древовидное отображение данных. Но я так понял основной вопрос почему использовал TIBXDataDriver вместо цепочки например TIBDataSet + TMemTableEh + TDBGridEh?
Для меня основное преимущество технологии DataDriver получилось в том, что позволило убрать DataSet'ы нижнего уровня и не тратить время на их настройку и дать большую гибкость. Теперь переключить клиента на использование технологии FIBPlus или доступ через ADO по идее несколько строчек кода. У себя в проекте тестировал работу через TIBXDataDriver и через TFIBDataDriver переключаясь через {$IFNDEF}.
Очень удобным оказалось автоматическое формирование update запросов (DynaSQLParams) с включением в запрос значений только измененных полей. Это позволило разрулить ситуацию, когда один клиент прошелся по данным и изменил одно поле, а в этот же момент другой клиент на этих же данных обновил другое поле.

Гаджимурадов Рустам

Vladislav Matvienko
Для вычисляемых в select полей, полей на основе вложенных подзапросов, полей с алиасами т.д. в текущем
виде серверная сортировка работать как я понял не будет?

Имелась в виду фильтрация, наверное ?
Это зависит только от "умности" фильтр-адаптера.

Да, опечатался. Имелось в виду конечно же серверная фильтрация.

Гаджимурадов Рустам

Vladislav Matvienko
Origin ... судя по справке это свойство обычно пустое.
.... при работе через IBX у меня всегда так

Нет. IBTable, небось, юзаешь? :)

Спасибо за замечание. Нет IBTable не использую:-)
Внутри TIBXDataDriver создается объект TIBQuery для доступа к данным. Сейчас еще раз перепроверил... Да, TIBQuery, и как я понимаю TIBDataSet, свойство Origin для простых полей заполняют - этот момент я упустил. Проблема как оказалось в том, что в поля TMemTableEh свойтво Origin, как вижу, из TIBQuery не копируется а в EhLib при построении Where условия используется Origin для поля из TMemTableEh.
Но в любом случае полностью это проблему не решает, т.к. для вычисляемых полей TIBQuery дает пустой Origin. И их нужно отдельно парсить - тут как раз обсуждаемый модуль в помощь.

А как с этим все таки в FibPlus или в ADO. Никто не знает? Проверить все руки не доходят...

Гаджимурадов Рустам

Vladislav Matvienko
Модуль uEhMyUtils.pas выкладываю у себя по адресу:
http://www.plaincad.com/EhLiB

Если оттестировал и оно того стоит - лучше пошли
Большакову, пусть выложит в стандартной поставке.
Заодно бета-тестеры смогут проверить.
Ну и мы поможем чем можем, потестим.


Спасибо! В конференцию EhLib я отписался по этой проблеме. Просто думаю здесь здесь быстрее получится проверить.


--
Vladislav Matvienko
http://www.PlainCAD.com - графический редактор для создания схем
Vladislav Matvienko
Дата: 09.06.2009 01:17:32
Оп... Извиняюсь за ссылку на модуль. Опечатался.
Правильный адрес
http://www.plaincad.com/EhLib/

--<BR> Vladislav Matvienko<BR>http://www.PlainCAD.com - графический редактор для создания схем