none
MVC3 + EF CF отбор по БД c большим количеством фильтров RRS feed

  • Вопрос

  • Добрый день.

    Есть сайт на MVC3 используется EF СF. Задача: 
    В БД есть таблица с 30 полями. Отбор предполагается вести по любому из полей, а так же могут комбинироваться. Подскажите как написать такой отбор. 

    Контроллер получает входные данные в виде объекта. И потом нужно перебрать все значения и сделать выборку. Вот тут вопрос, как к первому отбору:

    var data = db.DataContext.Table;

    как к этому отбору первому прибавить потом все остальные? вернее как следующие отборы сделать?


    7 августа 2012 г. 10:21

Ответы

  • Уже намного понятней. "Так мы выбрали все записи: var data = db.DataContext.Table" - пока-что ничего не выбрано, data это просто ссылка на коллекцию сущностей (если Table у вас типа DbSet), ни содержащая в себе ничего. Данные хранятся в базе и загружаете их тогда, когда cделаете запрос LINQ. Данные у Вас будут если

    var data = db.DataContext.Table.Select(i => i).ToArray();

    Это явная загрузка. Не явная, когда получите объект перечислителя (отложенная загрузка)

    var data = db.DataContext.Table.Select(i => i);

    При выполнении запроса, он транслируется в дерево выражений, после ORM (EF) транслирует его в SQL, и после выполнения SQL запроса, данные доходят вам. Отсюда вывод: дерево надо собрать вначале, когда используется фильтр, т.е собираете запрос, а уж потом отсылаете его и приходят нужные Вам данные. А если хотите конкретней, то уже нужен код.

    • Помечено в качестве ответа MakInnova 7 августа 2012 г. 11:51
    7 августа 2012 г. 11:00
    Модератор
  • IQueryable<User> query = Context.Users.AsQueryable(); if (!string.IsNullOrWhiteSpace(filter.UserName)) { query = query.Where(x => x.Username == filter.UserName); } if (filter.DateFrom.HasValue) { query = query.Where(x => x.CreatedDate >= filter.DateFrom.Value); } .... return query.ToList();//Выполнится запрос к базе 

    Также можете сделать обобщенный метод для поиска. Напр.

    public IList<User> Search(IList<Expression<Func<User, Boolean>>> searchClauses)
    {
       if (searchClauses == null) throw new ArgumentNullException("searchClauses");
    
       IQueryable<User> query = Context.Users.AsQueryable();
       foreach (Expression<Func<User, bool>> searchClause in searchClauses)
       {
          query = query.Where(searchClause);
       }
    
      return query.ToList();
    }

    Использование

    IList<Expression<Func<User, Boolean>>> predicates = new List<Expression<Func<User, bool>>>();
    Expression<Func<User, Boolean>> predicate = user => user.LastName.Contains("test");
    predicates.Add(predicate);
    
    IList<User> users = Search(predicates);

    • Помечено в качестве ответа MakInnova 7 августа 2012 г. 11:48
    • Изменено Alexander Kichkailo 7 августа 2012 г. 12:00
    7 августа 2012 г. 11:06

Все ответы

  • Не понятно, что Вы конкретно хотите, давайте переформулировав, по шагам.
    7 августа 2012 г. 10:32
    Модератор
  • Давайте

    Есть в БД таблица: Table

    Из нее надо выбрать только те записи, которые удовлетворяю выбору. Фильтр может состоять из 30  значений.

    Так мы выбрали все записи: var data = db.DataContext.Table; 

    теперь как из data выбирать по фильтру. Сначала один фильтр, потом из того что получилось, второй фильтр, потом  и т.д.?

    Так понятней?

    7 августа 2012 г. 10:39
  • Уже намного понятней. "Так мы выбрали все записи: var data = db.DataContext.Table" - пока-что ничего не выбрано, data это просто ссылка на коллекцию сущностей (если Table у вас типа DbSet), ни содержащая в себе ничего. Данные хранятся в базе и загружаете их тогда, когда cделаете запрос LINQ. Данные у Вас будут если

    var data = db.DataContext.Table.Select(i => i).ToArray();

    Это явная загрузка. Не явная, когда получите объект перечислителя (отложенная загрузка)

    var data = db.DataContext.Table.Select(i => i);

    При выполнении запроса, он транслируется в дерево выражений, после ORM (EF) транслирует его в SQL, и после выполнения SQL запроса, данные доходят вам. Отсюда вывод: дерево надо собрать вначале, когда используется фильтр, т.е собираете запрос, а уж потом отсылаете его и приходят нужные Вам данные. А если хотите конкретней, то уже нужен код.

    • Помечено в качестве ответа MakInnova 7 августа 2012 г. 11:51
    7 августа 2012 г. 11:00
    Модератор
  • IQueryable<User> query = Context.Users.AsQueryable(); if (!string.IsNullOrWhiteSpace(filter.UserName)) { query = query.Where(x => x.Username == filter.UserName); } if (filter.DateFrom.HasValue) { query = query.Where(x => x.CreatedDate >= filter.DateFrom.Value); } .... return query.ToList();//Выполнится запрос к базе 

    Также можете сделать обобщенный метод для поиска. Напр.

    public IList<User> Search(IList<Expression<Func<User, Boolean>>> searchClauses)
    {
       if (searchClauses == null) throw new ArgumentNullException("searchClauses");
    
       IQueryable<User> query = Context.Users.AsQueryable();
       foreach (Expression<Func<User, bool>> searchClause in searchClauses)
       {
          query = query.Where(searchClause);
       }
    
      return query.ToList();
    }

    Использование

    IList<Expression<Func<User, Boolean>>> predicates = new List<Expression<Func<User, bool>>>();
    Expression<Func<User, Boolean>> predicate = user => user.LastName.Contains("test");
    predicates.Add(predicate);
    
    IList<User> users = Search(predicates);

    • Помечено в качестве ответа MakInnova 7 августа 2012 г. 11:48
    • Изменено Alexander Kichkailo 7 августа 2012 г. 12:00
    7 августа 2012 г. 11:06
  • 	    IQueryable<User> query = Context.Users.AsQueryable();
    
                if (!string.IsNullOrWhiteSpace(filter.UserName))
                {
                    query = query.Where(x => x.Username == filter.UserName);
                }
    
                if (filter.DateFrom.HasValue)
                {
                    query = query.Where(x => x.CreatedDate >= filter.DateFrom.Value);
                }
    
                ....
    
                return query.ToList();//Выполнится запрос к базе

    Спасибо.

    А теперь скажите как проверку эту циклом сделать по всем фильтрам, что бы 30 условий не писать? 

    7 августа 2012 г. 11:51
  • Добавил обобщенный метод в свой ответ (см. выше). Дайте знать, если он Вам не подходит.
    7 августа 2012 г. 12:02
  • Спасибо Вам за код, но для меня он слишком сложный пока. Про класс Expression мало у меня знаний. Может есть что попроще?
    7 августа 2012 г. 14:10
  • Проще предложить не могу, только сложнее). Может кто-нибудь из сообщества что-нибудь посоветует. В любом случае, учиться нужно всегда.  Вот ссылка, которая может быть полезна в этом:

    http://msdn.microsoft.com/ru-ru/library/bb386964


    8 августа 2012 г. 9:14
  • "Спасибо Вам за код, но для меня он слишком сложный пока. Про класс Expression мало у меня знаний. Может есть что попроще?" - проще собирать запросы конкатенацией с использованием ADO.NET, не используя ORM, но это плохо. Лучше постепенно учить, как разберётесь с делегатами и лямбда-выражениями, деревья выражений не будут казаться сложными, нужно просто некоторое время поработать.
    8 августа 2012 г. 11:52
    Модератор