Reputation: 1198
I have a variable number of "filters" to apply to an entity collection, and these filters are stored in a List. Right now, I'm doing the following:
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();
Unfortunately, this causes a huge performance issue. I know somebody out there has a better solution... What do you guys think?
EDIT
Running my application with the code above takes around 30 seconds to execute, but if do the following:
items.Where(item => item.Type.ToLower().Trim() == "new" ||
item.Type.ToLower().Trim() == "old" ||
item.Type.ToLower().Trim() == "current");
my application executes in about 4 seconds. Can anyone think of a solution that can match this performance or at least fill me in on why the results are so drastically different? FYI, I'm binding my data to a grid with multiple grids nested inside... a small improvement can go a long way.
Upvotes: 2
Views: 3410
Reputation: 149010
Sounds like what you want is this:
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()));
If you're having issues with this, you might want to try using an array instead:
string[] filterList = new string[] {"new", "old", "current"};
var filteredItems = items.Where(i => filterList.Contains(i.Type.ToLower()));
Update: Here's another strategy which generates a filter expression dynamically:
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);
Upvotes: 4
Reputation: 152521
You could do a join to filter the items:
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;
Upvotes: 2