How to build a custom expression for an advanced search screen

≡放荡痞女 提交于 2021-02-19 06:48:11

问题


I am building an advanced search screen and am using nHibernate to query the DB. I have already built my DataAccess layer and have built a generic method which works great - I pass in an expression to be used as a predicate and passes back a collection of an object that matches the predicate:

public object LoadByPredicate<T>(Expression<Func<T, bool>> predicate) where T : class

Example usage is:

var items = _query.LoadByPredicate<StaticTypes>(x => x.StaticName == type) as List<StaticTypes>;

This is great.

I am now building an advanced search screen on my application where a user can search by between one and 20 different options to return matching "Products". I.e. The Product class has 20 properties and they can search by a combination of Name, Reference, Description, Value etc.....

I'd like to build a mechanism that will construct an expression for me that I can pass into my "LoadByPredicate" method above.

So far I proved this will work:

var type = typeof(Model.Product);
var property = type.GetProperty("ProductMetalProductType");
var parameter = Expression.Parameter(typeof(Model.Product), "x");

Expression<Func<Model.Product, bool>> predicate =
     (Expression<Func<Model.Product, bool>>)Expression.Lambda(
        Expression.Equal(
            Expression.MakeMemberAccess(parameter, property),
           Expression.Constant(metalProdType)),
                parameter);

This works great for one item the property called "ProductMetalProductType". However I can't see how I can expand this without writing a HUGE amount of code. How can I write some code where I say on the lines of "if Product Metal type is not empty" add an extra expression to refine the search predicate by that?

Or am I going down the wrong track with the way I am constructing my expression?

Thanks in advance


回答1:


You can do like this:

public class Program
{
    static void Main(string[] args)
    {
        var parameters = new Dictionary<string, object>();
        parameters.Add("ProductMetalProductType", 1);
        parameters.Add("IsActive", true);
        parameters.Add("Name", "New cool product");

        var expr = GenerateExpression<Product>(parameters);
        Console.WriteLine("Result expression:");
        Console.WriteLine(expr.ToString());
    }

    private static Expression<Func<T, bool>> GenerateExpression<T>(Dictionary<string, object> properties)
    {
        var type = typeof(T);
        List<Expression> expressions = new List<Expression>();
        var parameter = Expression.Parameter(typeof(T), "x");
        foreach (var key in properties.Keys)
        {
            var val = properties[key];
            var property = type.GetProperty(key);

            var eqExpr = Expression.Equal(Expression.MakeMemberAccess(parameter, property), Expression.Constant(val));

            expressions.Add(eqExpr);
        }

        Expression final = expressions.First();
        foreach (var expression in expressions.Skip(1))
        {
            final = Expression.And(final, expression);
        }

        Expression<Func<T, bool>> predicate =
            (Expression<Func<T, bool>>) Expression.Lambda(final, parameter);

        return predicate;
    }
}

public class Product
{
    public int ProductMetalProductType { get; set; }

    public bool IsActive { get; set; }

    public string Name { get; set; }
}

Here is working fiddle - http://dotnetfiddle.net/t0a9yA

Basically you can fill Dictionary with needed parameters, then generate expression based on that dictionary. Dictionary key is a property name, and value is value for filtering.



来源:https://stackoverflow.com/questions/21801702/how-to-build-a-custom-expression-for-an-advanced-search-screen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!