开发者

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);
        }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜