2013-07-25 3 views
1

У меня есть переменное количество «фильтров» для применения к коллекции сущностей, и эти фильтры хранятся в списке. Сейчас я делаю следующее:LINQ where clause - сравнить набор строк

IQueryable<Items> items = SharedContext.Context.Items.GetAll(); 
    //This list is dynamic, but shown static here for simplicity 
    IEnumerable<Items> filterList = new List<string>(){"new", "old", "current"}; 
    IEnumerable<Item> items_temp = new List<Item>(); 
    foreach (string type in filterList) 
    { 
     var temp = items.Where(i => i.Type.ToLower().Trim() == type.ToLower().Trim()); 
     items_temp = items_temp.Union(temp); 
    } 
    items = items_temp.AsQueryable(); 

К сожалению, это вызывает огромную проблему с производительностью. Я знаю, что у кого-то есть лучшее решение ... Что вы, ребята, думаете?

EDIT
Запуск моего приложения с кодом выше занимает около 30 секунд, чтобы выполнить, но если сделать следующее:

items.Where(item => item.Type.ToLower().Trim() == "new" || 
         item.Type.ToLower().Trim() == "old" || 
         item.Type.ToLower().Trim() == "current"); 

мое приложение выполняет примерно 4 секунды. Может ли кто-нибудь подумать о решении, которое может соответствовать этой производительности или, по крайней мере, наполнить меня тем, почему результаты настолько сильно отличаются? FYI, я привязываю свои данные к сетке с несколькими сетками, вложенными внутри ... небольшое улучшение может пройти долгий путь.

ответ

4

Похоже, что вы хотите, это:

var items = SharedContext.Context.Items.GetAll(); 
IEnumerable<string> filterList = new List<string>(){"new", "old", "current"}; 
var filteredItems = items.Where(i => filterList.Contains(i.Type.ToLower())); 

Если у вас возникли проблемы с этим, вы можете попробовать использовать массив вместо:

string[] filterList = new string[] {"new", "old", "current"}; 
var filteredItems = items.Where(i => filterList.Contains(i.Type.ToLower())); 

Update : Вот еще одна стратегия, которая динамически генерирует выражение фильтра:

var filterList = new[] { "new", "old", "current" }; 
var param = Expression.Parameter(typeof(Item)); 
var left = 
    Expression.Call(
     Expression.Call(
      Expression.PropertyOrField(param, "Type"), 
      typeof(string).GetMethod("ToLower", Type.EmptyTypes)), 
     typeof(string).GetMethod("Trim", Type.EmptyTypes)); 
var filterExpr = (Expression<Func<Item, bool>>)Expression.Lambda(
    filterList 
     .Select(f => Expression.Equal(left, Expression.Constant(f))) 
     .Aggregate((l, r) => Expression.OrElse(l, r)), 
    param); 
var filteredItems = items.Where(filterExpr); 
+0

+1 за предложение чистого раствора. Хотя, это не сильно повлияло на время выполнения. См. Мое редактирование. –

+0

@MrJones Это должно помочь немного, если вы выполняете 'Where' на' IQueryable' напрямую. Это должно привести к предложению 'IN' в SQL. Вы также можете попытаться сделать что-то, используя «Выражения». См. Мой обновленный ответ. –

+0

Только то, что я искал. Спасибо за обновление. Что вы имеете в виду, выполнив 'Where' на' IQueryable' напрямую? Разве я этого не делаю, занимаясь предметами. Где (...)? –

2

Вы могли бы сделать присоединиться к фильтрации элементов:

IEnumerable<Items> filterList = new List<string>(){"new", "old", "current"};   
IQueryable<Items> items = SharedContext.Context.Items.GetAll(); 

var filteredItems = from i items 
        join f in filterList 
         on i.Type.ToLower().Trim() equals t.ToLower().Trim() 
        select i; 
+0

Интересный подход. Это было действительно быстрее. Это привело к сокращению времени выполнения до 20 секунд, но все еще не совсем там. –