Because the project needs to use Linq to query data, but when performing multi-condition queries, you need to use a lot of if (...! = String. empty. The following two methods are found on the Internet: one is a class written by a foreigner, which is difficult to use; the other is to provide an extension method with a parameter of a type, when this method is called, reflection is used to traverse the attributes of this type, dynamic query parameters are used to compare with the attribute values, and dynamic lambda expressions are constructed. This is also flawed, that is, all attributes of the type need to be traversed, and the construction of lambda expressions can only build = type expressions, there are limitations. So I figured out a way to call it. I only need a line of code, and lambda expressions can be built at will, and now we enter the topic.
Suppose there is a type of Employee, And this type has a set of employeeList, and there is such an extension method Wheres Based on the IEnumerable <T> type (will be introduced later), how to use
One line of code employeeList. wheres (o => o. name = "a" & o. salary> 5000 & o. inDate> = DateTime. now & o. address. contains ("Beijing") implements the following code:
If (! String. IsNullOrEmpty (name ))
{
EmployeeList. Where (o => o. Name = name );
}
If (salary! = Null) the parameter is set to null.
{
EmployeeList. Where (o => o. Name = name );
}
If (inDate! = Null)
{
EmployeeList. Where (o => o. InDate> = inDate );
}
If (! String. IsNullOrEmpty (address ))
{
EmployeeList. Where (o => o. Address. Contains ("Beijing "));
}
Because the Linq Lambda expression will be parsed into a binary tree of an expression during running, this tree only allows the child nodes on the left to exist in the BinaryExpression subnode, while the child nodes on the right do not have the BinaryExpression subnode, however, the MemberExpression subnode (o. name = "a" is a BinaryExpression, o. name and "a" are binaryexpressions ). So employeeList. wheres (o => o. name = "a" & o. salary> 5000 & o. inDate> = DateTime. now & o. address = "Beijing") will be parsed into a binary tree for example:
We only need to find the red node, get the value of the blue node, and then construct a dynamic Lambda expression. The method for obtaining the node is as follows:
/// <Summary> /// parse Expression tree /// </summary> /// <param name = "tree"> </param> /// <returns> </returns> private static Stack <Expression> DivideBinaryExpression (Expression expression) {Stack <Expression> stack = new Stack <Expression> (); if (expression. nodeType! = ExpressionType. andAlso) // to simplify the Call Code, only the root node is allowed as & {stack. push (expression);} else {BinaryExpression tree = expression as BinaryExpression; while (tree! = Null & tree. NodeType = ExpressionType. AndAlso) {stack. Push (tree. Right); if (tree. Left. NodeType! = ExpressionType. AndAlso) {stack. Push (tree. Left);} tree = tree. Left as BinaryExpression; // loop traversal expression} return stack ;}View Code
Then, dynamically construct the Lambda expression based on the obtained node. The method is as follows:
/// <Summary> /// query multiple where clauses /// </summary> /// <typeparam name = "TSource"> Object Type </typeparam> /// <typeparam name = "TResult"> return type of Expression </typeparam> // <param name = "t"> entity set </param> /// <param name = "expression"> expression </param> // <returns> object set </returns> public static IEnumerable <TSource> Wheres <TSource> (this IEnumerable <TSource> t, expression <Func <TSource, bool> expression) {foreach (Expression e in DivideBinaryExpression (expression. Body) {object expressionValue = null; if (e as BinaryExpression )! = Null) {BinaryExpression be = e as BinaryExpression; expressionValue = LambdaExpression. lambda (be. right ). compile (). dynamicInvoke ();} else // to process like o. address. special node {MethodCallExpression mce = e as MethodCallExpression; expressionValue = LambdaExpression. lambda (mce. arguments [0]). compile (). dynamicInvoke ();} if (expressionValue! = Null) {if (! String. isNullOrEmpty (expressionValue. toString () t = t. where (Expression. lambda <Func <TSource, bool> (e, expression. parameters ). compile () ;}} return t ;}View Code
You only need to call a line of code as mentioned above. Although it is not perfect, it can solve at least 90% of the requirements.