问题
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