Simple linq question: How to filter a source afterwards?
I have an 3-layered project, so that all Linq-Querys himself are in the DAL. Now I have a filter function implemented in the Desig-Layer and want easily filter there, but how?
Business.UserHandling uh = new Business.UserHandling();
List<DAL.Benutzer> users = uh.GetUserOverview();
gridUserOverview.AutoGenerateColumns = false;
gridUserOverview.DataSource = users;
gridUserOverview.DataBind();
How can I user something like "users = users.Where("bla = 1")"?
I tried:
Business.UserHandling uh = new Business.UserHandling();
List<DAL.Benutzer> users = uh.GetUserOverview();
var filters = new Dictionary<string, object>();
filters.Add(Request.QueryString["value"], Request.QueryString["text"]);
users = users.Where(user => filters.All(filter => user.GetType().GetProperty(filter.Key).GetValue开发者_如何学Go(user, null) == filter.Value)).ToList();
gridUserOverview.AutoGenerateColumns = false;
gridUserOverview.DataSource = users;
gridUserOverview.DataBind();
But it fails... I filtered on "UserID = 1", I have 2 Users, the filter should be filter 1 of these 2. But the return is 0 users.
In order to use a dynamic filter you can build a dictionary and verify the filter by reflection:
var filters = new Dictionary<string, object>();
filters.Add("bla", 1);
users.Where(user => filters.All(filter => user.GetType().GetProperty(filter.Key).GetValue(user, null) == filter.Value));
Edit Support all types convertible from string:
var users = new List<User>();
users.Add(new User {Age = 1 });
users.Add(new User { Age = 2 });
var filters = new Dictionary<string, string>();
filters.Add("Age", "1");
var filtered = users.Where(user => filters.All(filter =>
{
var propertyInfo = user.GetType().GetProperty(filter.Key);
return Equals(propertyInfo.GetValue(user, null) , Convert.ChangeType(filter.Value, propertyInfo.PropertyType));
}));
Assert.AreEqual(1, filtered.Count());
You could change GetUserOverview to accept an expression, which would allow you to do custom filtering.
Example
public List<Benutzer> GetUserOverview(Func<Benutzer, bool> filter)
{
//get your users however you were getting them
var _result = new List<Benutzer>();
_result = _result.Where(filter);
return _result;
}
And that would let you do this:
List<DAL.Benutzer> users = uh.GetUserOverview(user => user.bla == 1);
UPDATE
If you need to dynamically build your filter you can do it this way:
Expression<Func<Benutzer, bool> finalFilter;
if (doFirstFilter)
{
Expression<Func<Benutzer, bool> firstFilter = (user) => user.blah == 1;
}
if (doSecondFilter)
{
Expression<Func<Benutzer, bool> secondFitler =
(user) => user.other == "whatever";
finalFilter = Expression.Lambda<Func<Benutzer, bool>>(
Expression.And(firstFilter, secondFilter));
}
var users = uh.GetUserOverview(finalFilter.Compile());
You can do all kinds of crazy stuff with Expressions.
Have you tried this useful bit of code taken from here
public static IQueryable<T> AddEqualityCondition<T, V>(this IQueryable<T> queryable,string propertyName, V propertyValue)
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
IQueryable<T> x = queryable.Where<T>(
Expression.Lambda<Func<T, bool>>(
Expression.Equal(Expression.Property(
pe,
typeof(T).GetProperty(propertyName)),
Expression.Constant(propertyValue, typeof(V)),
false,
typeof(T).GetMethod("op_Equality")),
new ParameterExpression[] { pe }));
return (x);
}
精彩评论