Организация фильтрации в приложении .NET
От: Аноним  
Дата: 06.11.09 09:16
Оценка:
Доброго времени суток!
Вопрос такой: как по вашему мнению правильнее всего организовать фильтрацию строк в формах, где отображаются списки бизнес-сущностей, загружаемых из базы данных в приложении на .NET. Например, есть диалог "Заказы". В нем есть Grid со списком заказов. В том же диалоге есть кнопка "фильтр", по нажатию на которую открывается диалог настройки фильтра (где можно задать номер или часть номера, дату заказа или интервал дат, заказчика или список заказчиков, общую сумму заказ или интервал сумм). Поскольку заказов может быть ОЧЕНЬ много и затягивать из СУБД их все слишком расточительно, то применение фильтра должно в конечном счете приводить к модификации текста запроса, уходящего в СУБД.
Интересует вариант с 3-хзвенной архитектурой, когда условие фильтрации (дерево выражений?) надо передавать с клиента на сервер приложений в форме отличной от SQL-запроса.
Я пока вижу часть решения так (для случая с "Заказами"):
1. Есть класс "Заказы", обвешанный атрибутами (пока не знаю какими именно), хранящими метаинформацию о бизнес-сущности "Заказ".
2. Некий контроллер фильтра при инициализации получает переменную типа Type:
FilterController fc = new FilterController(typeof(ЗАКАЗЫ))

и на основе информации, содержащейся в атрибутах класса ЗАКАЗЫ настраивает FilterControl (наследник UserControl'а).
3. Пользователь, работая с FilterControl'ом, настраивает условия фильтрации в контроллере фильтра.
4. На выходе контроллер фильтра должен преобразовать полученное условие фильтрации в виде некоторого дерева выражений, пригодного для сериализации (его же надо передать посредствам WCF на сервер приложений) и интерпретации в SQL-код в слое DAL.

По-моему махровым велосипедом попахивает... LINQ, мне кажется, не совсем то, что нужно: хочется иметь один класс контроллера фильтров для всех классов бизнес-сущностей...
Re: Организация фильтрации в приложении .NET
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.11.09 09:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Доброго времени суток!

А>Вопрос такой: как по вашему мнению правильнее всего организовать фильтрацию строк в формах, где отображаются списки бизнес-сущностей, загружаемых из базы данных в приложении на .NET. Например, есть диалог "Заказы". В нем есть Grid со списком заказов. В том же диалоге есть кнопка "фильтр", по нажатию на которую открывается диалог настройки фильтра (где можно задать номер или часть номера, дату заказа или интервал дат, заказчика или список заказчиков, общую сумму заказ или интервал сумм). Поскольку заказов может быть ОЧЕНЬ много и затягивать из СУБД их все слишком расточительно, то применение фильтра должно в конечном счете приводить к модификации текста запроса, уходящего в СУБД.
А>Интересует вариант с 3-хзвенной архитектурой, когда условие фильтрации (дерево выражений?) надо передавать с клиента на сервер приложений в форме отличной от SQL-запроса.
А>Я пока вижу часть решения так (для случая с "Заказами"):
А>1. Есть класс "Заказы", обвешанный атрибутами (пока не знаю какими именно), хранящими метаинформацию о бизнес-сущности "Заказ".
А>2. Некий контроллер фильтра при инициализации получает переменную типа Type:
А>
А>FilterController fc = new FilterController(typeof(ЗАКАЗЫ))
А>

А>и на основе информации, содержащейся в атрибутах класса ЗАКАЗЫ настраивает FilterControl (наследник UserControl'а).
А>3. Пользователь, работая с FilterControl'ом, настраивает условия фильтрации в контроллере фильтра.
А>4. На выходе контроллер фильтра должен преобразовать полученное условие фильтрации в виде некоторого дерева выражений, пригодного для сериализации (его же надо передать посредствам WCF на сервер приложений) и интерпретации в SQL-код в слое DAL.

А>По-моему махровым велосипедом попахивает... LINQ, мне кажется, не совсем то, что нужно: хочется иметь один класс контроллера фильтров для всех классов бизнес-сущностей...


Не изобретай велосипеды, смотри .NET Ria Services и ADO.NET Data Services
Re[2]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 06.11.09 11:51
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Не изобретай велосипеды, смотри .NET Ria Services и ADO.NET Data Services
ОК. Сейчас пойду читать.
А это с приложениями, где клиент на WinForm написан подходит?
Re[3]: Организация фильтрации в приложении .NET
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.11.09 12:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, gandjustas, Вы писали:

G>>Не изобретай велосипеды, смотри .NET Ria Services и ADO.NET Data Services
А>ОК. Сейчас пойду читать.
А>А это с приложениями, где клиент на WinForm написан подходит?

1)ADO.NET Data Services — подходят
2).NET Ria Services — неочень
Re[4]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 06.11.09 14:06
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>1)ADO.NET Data Services — подходят
G>2).NET Ria Services — неочень
У меня клиент на WinForms, к тому же сильно не хочется EF завязываться, как и на любой другой тяжелый ORM...
Может еще варианты есть?
Re: Организация фильтрации в приложении .NET
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 06.11.09 16:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А><skipped>


Самый нормальный способ — это написание LINQ-провайдера, но он весьма трудоёмок, особенно для тех, кто никогда не занимался ничем подобным. С другой стороны, написав его один раз, можно будет с минимальными переделками использовать его в других проектах...
[КУ] оккупировала армия.
Re[2]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 06.11.09 20:16
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Самый нормальный способ — это написание LINQ-провайдера, но он весьма трудоёмок, особенно для тех, кто никогда не занимался ничем подобным. С другой стороны, написав его один раз, можно будет с минимальными переделками использовать его в других проектах...


А чем мне свой LINQ-провайдер поможет? Я пока с MSSQL работаю, для него вроде LinqToSql самое оно... Или я ошибаюсь?
Тут другой вопрос: как с помощью того же LINQ сформировать запрос, который будет модифицироваться в рантайме в зависимости от настроек, которые пользователь сделал через UserControl? Можно ссылочку на пример сценария типа:

1. select * from MyTable where 1 = 1


Потом пользователь жмет на кнопку button1 и получаем запрос типа

2. select * from MyTable where 1 = 1 and DateDoc='20091107'


Ну только все это естественно с LINQ, а не с SQL-кодом?

Хотя, как я уже писал выше, с LINQ завязываться не очень хочется. Какой-то он недоделанный без DML...
Re[3]: Организация фильтрации в приложении .NET
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 06.11.09 20:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>1. select * from MyTable where 1 = 1
А>


var result = context.MyTable(); //возвращает IQueryable<MyTableEntity>



А>Потом пользователь жмет на кнопку button1 и получаем запрос типа


А>
А>2. select * from MyTable where 1 = 1 and DateDoc='20091107'
А>

if (dateDoc != null)
{
    result = result.Where(x => x.DateDoc == dateDoc); //опять его же возвращает
}


Вот таким макаром в динамике строить предикаты из гуя. Затем твой провайдер должен распарсить полученное дерево в нечто вроде AST, сереализовать его и отправить на AppServer. Там по этому AST либо восстанавливается запрос и кормится Linq2SQL, либо руками генерится SQL и всё это добро едет в БД. Потом результаты маппятся в соответствующие объекты и отправляются обратно клиенту. В вашем случае всё очень несложно, поскольку не надо обрабатывать агрегатные операции, проекции и т.п.. Я бы сказал, работа на недельку-полторы, если вы этим раньше не занимались, или пару дней, если уже варились раньше в этом соку — тут порог входа высок...

А>Хотя, как я уже писал выше, с LINQ завязываться не очень хочется. Какой-то он недоделанный без DML...

В вашем случае это неважно, а в случае своего провайдера вы можете приделать DML (да и вообще всё что угодно) сами...
[КУ] оккупировала армия.
Re[4]: Организация фильтрации в приложении .NET
От: IB Австрия http://rsdn.ru
Дата: 07.11.09 08:49
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Вот таким макаром в динамике строить предикаты из гуя. Затем твой провайдер должен распарсить полученное дерево в нечто вроде AST, сереализовать его и отправить на AppServer.

Зачем так сложно? На AppServer можно отправить обычный объект, содержащий все условия фильтрации (тот же DateDoc), и AppServer на этих условиях построит свой линковский запрос.
В этой задаче пока нет ничего, чтобы потребовалось писать свой провайдер. Этим можно только из любви к искусству заниматься.
Мы уже победили, просто это еще не так заметно...
Re[3]: Организация фильтрации в приложении .NET
От: IB Австрия http://rsdn.ru
Дата: 07.11.09 09:05
Оценка: 6 (1)
Здравствуйте, Аноним, Вы писали:

А>Тут другой вопрос: как с помощью того же LINQ сформировать запрос, который будет модифицироваться в рантайме в зависимости от настроек, которые пользователь сделал через UserControl?

Элементарно. LINQ — ленив, это означает, что запрос физически уедет на сервер БД только в тот момент, когда тебе потребуется результат этого запроса. До этого модифицировать его можно как угодно.

Пример:

var q = from t in context.GetTable<MyTable>() // запрос еще в приложении
        where t.Date > Filter.StartDate
        select t; 

if (Filter.IsSalaryFiltered) // запрос по прежнему на appSever
    q = q.Where(t=>t.Salary > Filter.Salary)
         .Select(t=>t);

foreach(var item in q) // а вот здесь в СУБД поехал полностью сформированный сиквельный запрос.
{
    ....
}
Мы уже победили, просто это еще не так заметно...
Re[3]: Организация фильтрации в приложении .NET
От: Gollum Россия  
Дата: 07.11.09 09:48
Оценка:
Здравствуйте, <Аноним>

Ну вот тут ниже Ваня написал

var q = from t in context.GetTable<MyTable>() // запрос еще в приложении
        where t.Date > Filter.StartDate
        select t;


Весь вопрос в том — что из себя представляет context. Если это linqToSql DataContext прямо на клиенте, то тогда никакой трехзвенки не получится.

Можно оставить DataContext на сервере. Тогда нам нужно будет на клиенте выставлять наружу некий IQueryable, который бы умел принимать запрос, отправлять его на сервер. Из известных средств навскидку припомню .NET RIA Services, ADO.NET Data Services. Можно также написать свой провайдер IQueryable, но это весьма трудоемкая и нетривиальная задача.

Если не хочется с этим связываться, есть еще один путь.
Можно на сервер передавать всего лишь expression tree для фильтрации запроса. Т.е. пусть у нас запрос на сервере выглядит так:

var q = from u in dataContext.Users select u;


Мы можем с клиента получить условия фильтрации в виде expression tree (вообще они не сериализуются из коробки, но после приплясывания с бубном можно) и применить его в виде

var filteredQuery = q.Where(expressionTreeFromClient);


Как создавать expression tree — это отдельный вопрос, ничего сложного там нет, все довольно нудно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Eugene Agafonov on the .NET

Re[4]: Организация фильтрации в приложении .NET
От: IB Австрия http://rsdn.ru
Дата: 07.11.09 18:04
Оценка: +1
Здравствуйте, Gollum, Вы писали:

G>Можно оставить DataContext на сервере. Тогда нам нужно будет на клиенте выставлять наружу некий IQueryable, который бы умел принимать запрос, отправлять его на сервер.

Зачем так сложно? С клиента на сервер достаточно передать простой объект типа Filter, а уж подставить его данные в линковский запрос на сервере — не бином ньютона.
Нет никакой разницы, прямо на клиенте из данных контрола генерить запрос или передать эти данные на сервер и строить на основе этих данных запрос там, просто для второго случая не нужно свой IQueryable изобретать и учиться его сериализовать. Что вас всех так тянет свой LINQ-провайдер на ровном месте писать?
Мы уже победили, просто это еще не так заметно...
Re[5]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 09.11.09 09:18
Оценка:
Здравствуйте, IB, Вы писали:

IB>Зачем так сложно? С клиента на сервер достаточно передать простой объект типа Filter, а уж подставить его данные в линковский запрос на сервере — не бином ньютона.

Это все классно, но какова структура класса Filter?
По идее фильтр — набор выражений сравнения (=, <>, between and, in, >, <, is null, и т.д.), соединенных между собой булевыми операторами (and, or). Ну и там всякие еще not добавляются....
Так вот в операции сравнения должны в качестве операндов присутствовать значения. Это могут быть строки, целые и разные другие нецелые числа, даты, GUID'ы и пр. Хранить все эти значения в переменных типа Object? А как WCF-контракт для таких значений объявлять? WCF, насколько я знаю, не сможет из object развернуть, например, DateTime.
Преобразовать все значения к типу string тоже не хочется...
Re[6]: Организация фильтрации в приложении .NET
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.11.09 09:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, IB, Вы писали:


IB>>Зачем так сложно? С клиента на сервер достаточно передать простой объект типа Filter, а уж подставить его данные в линковский запрос на сервере — не бином ньютона.

А>Это все классно, но какова структура класса Filter?
А>По идее фильтр — набор выражений сравнения (=, <>, between and, in, >, <, is null, и т.д.), соединенных между собой булевыми операторами (and, or). Ну и там всякие еще not добавляются....
А>Так вот в операции сравнения должны в качестве операндов присутствовать значения. Это могут быть строки, целые и разные другие нецелые числа, даты, GUID'ы и пр. Хранить все эти значения в переменных типа Object? А как WCF-контракт для таких значений объявлять? WCF, насколько я знаю, не сможет из object развернуть, например, DateTime.
А>Преобразовать все значения к типу string тоже не хочется...

Открой для себя KnownTypeAttribute
Re[7]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 09.11.09 09:42
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Открой для себя KnownTypeAttribute


А чем мне это поможет? Я СИСТЕМНЫЙ тип object должен пометить этим атрибутом???? Или мне свою иерархию типов заводить? Вариант конечно, но изврат ведь!
Re[8]: Организация фильтрации в приложении .NET
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.11.09 09:47
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, gandjustas, Вы писали:


G>>Открой для себя KnownTypeAttribute


А>А чем мне это поможет? Я СИСТЕМНЫЙ тип object должен пометить этим атрибутом????

Читай MSDN. Ты должен пометить сериализуемый класс и указать ему какие типы будут известны при сериализации.
тогда при помещении в свойство типа object значения известного типа оно будет корректно сериализовано.

А>Или мне свою иерархию типов заводить? Вариант конечно, но изврат ведь!

Для фильтров — заводить.
Re[9]: Организация фильтрации в приложении .NET
От: Аноним  
Дата: 09.11.09 10:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Читай MSDN. Ты должен пометить сериализуемый класс и указать ему какие типы будут известны при сериализации.

G>тогда при помещении в свойство типа object значения известного типа оно будет корректно сериализовано.

Т.е. если я объявлю такой интерфес:

[KnownTypeAttribute(int)][KnownTypeAttribute(decimal)][KnownTypeAttribute(string)]
public interface IConditionValue
{
  public object Value { get; set; }
}


То свойству Value можно будет присваивать значения типов int, decimal, string и объекты классов, реализующих интерфейс IConditionValue будут нормально сериализовываться/десериализовываться????
Я читал про KnownTypeAttribute, но по-моему это касалось только отношений наследования, а не агрегирования... Я чего-то недочитал?
Re[10]: Организация фильтрации в приложении .NET
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.11.09 11:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я читал про KnownTypeAttribute, но по-моему это касалось только отношений наследования, а не агрегирования... Я чего-то недочитал?


http://msdn.microsoft.com/en-us/library/ms730167.aspx
Re[5]: Организация фильтрации в приложении .NET
От: Gollum Россия  
Дата: 09.11.09 12:23
Оценка:
Здравствуйте, IB, Вы писали:

IB>Зачем так сложно? С клиента на сервер достаточно передать простой объект типа Filter, а уж подставить его данные в линковский запрос на сервере — не бином ньютона.


Ты до конца, видимо, мое сообщение не дочитал
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Eugene Agafonov on the .NET

Re[6]: Организация фильтрации в приложении .NET
От: IB Австрия http://rsdn.ru
Дата: 09.11.09 13:30
Оценка:
Здравствуйте, Gollum, Вы писали:

G>Ты до конца, видимо, мое сообщение не дочитал

Дочитал.. )
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.