Linq to Entity experience: expression conversion (revised version) Linq to Entity experience: expression Conversion

Source: Internet
Author: User

I have shared the problem of expression conversion in my previous article (Linq to Entity experience: expression conversion). I thought the problem was solved, but I found that the problem was not solved in actual application, it is not completely unsolved, but not practical. The problem is as follows:

Let's take a look at the problem.Objective of expression Conversion:

In fact, we are so difficult to convert expressions to convert the Expression Tree conditions we write on the UI Layer to the expressions recognized by EntityFramework, this is because EntityFramework can only recognize entity objects of EntityFramework. If we prioritize databases, these entities are automatically generated, and our business systems often have business entities independent of databases, the two are the same in some cases, but in some cases they are very different. This is the reason for conversion, such as TestExpression. model. courier is a business entity, My. frameWork. utilities. test. courier is a database object. See the following requirements:

The UI Layer collects conditions for data search:

Expression <Func <TestExpression. Model. Courier, bool> two2 = c => c. Value. StartsWith (mes. Name );

To query a database, you need to convert the above expression tree to an Expression Tree that the EntityFramework can recognize below. Note: although the two expressions have the same object name, they have different namespaces.

Expression <Func <My. FrameWork. Utilities. Test. Courier, bool> two2 = c => c. Value. StartsWith (mes. Name );


Problem:

The StartsWith parameter is a string. We know that this string is different from most other basic metadata. It is not a value type but a reference type. Therefore, when the external local variable is passed as a parameter to the expression, memberAccess occurs during Expression Tree parsing. in the previous article, only the ConstantExpression parameter type is supported, and the MemberExpression here reports an exception during parsing ., For example, the following expression can be converted and "min" is passed directly. This is a ConstantExpression type parameter:

Expression <Func <TestExpression. Model. Courier, bool> two2 = c => c. Value. StartsWith ("min ");

But if you write it like this, it won't work:

String name = "min ";
Expression <Func <TestExpression. Model. Courier, bool> two2 = c => c. Value. StartsWith (name );

And the expression mentioned by the switch in this article does not work either: (the mes below is a class)

Expression <Func <TestExpression. Model. Courier, bool> two2 = c => c. Value. StartsWith (mes. Name );


How can this problem be solved?Here we will share with you the process of solving the problem.

1: Since the parameter is ConstantExpression, can the parameter originally not ConstantExpression be changed to ConstantExpression.
With this idea, I thought that since mes. name is the attribute of an object. If you perform the deep copy of the character string for this attribute, it will not be able to get rid of the class reference type problem. Although the class problem is eliminated, however, it is found that the string itself is a reference type, so whether it is converted or not, it cannot be converted into a non-ConstantExpression, that is, the following processing is futile.

 

Public static class StringDeepClone
{
Public static string GetStringDeepClone (this string source)
{
String result = string. Empty;
Using (MemoryStream MS = new MemoryStream ())
{
BinaryFormatter bf = new BinaryFormatter ();
Bf. Serialize (MS, source );
Source = null;
Ms. Position = 0;
Result = (string) bf. Deserialize (MS ));
}
Return result;
}
}

2: since the problem with the reference type is that MemberAccess occurs, can MemberExpression with local variables be parsed?

Expression <Func <TestExpression. Model. Courier, bool> two2 = c => c. Value. StartsWith (mes. Name );

Like this line of code, there is no mes type information in the context of the entire expression. It is an external local variable, which increases the difficulty of parsing, later I consulted his head (http://cnblogs.com/ninputer), he provided me with a conversion method, and later did not continue to study because the code is not complete, the code function is to parse this MemberExpression with local variables.

3: since the resolution of MemberExpression fails, can I directly extract the value from MemberExpression?
I searched the internet and found that a foreigner provided a solution:

Private static object GetMemberExpressionValue (MemberExpression member)
{
Var objectMember = Expression. Convert (member, typeof (object ));
Var getterLambda = Expression. Lambda <Func <object> (objectMember );
Var getter = getterLambda. Compile ();
Return getter ();
}

The idea of this method is to convert MemberExpression into an executable Lambda expression and get the calculated value by executing the Lambda expression.

With the above method, we need to modify the original Parsing Method: mainly to judge the type of the parameter expression, if it is a value type, it goes through the previous logic, if it is a reference type, we need to extract values from MemberExpression, and solve the problem with the data.

Case ExpressionType. Call:
{
Var be = (MethodCallExpression) node;
Var resultValue = string. Empty;
Switch (be. Arguments [0]. NodeType)
{
Case ExpressionType. MemberAccess:
Var exprssion = GetMemberExpressionValue (MemberExpression) be. Arguments [0]);
If (null! = Exprssion)
{
ResultValue = exprssion. ToString ();
}
Break;
Case ExpressionType. Constant:
ResultValue = (ConstantExpression) be. Arguments [0]). Value. ToString ();
Break;
}
Var expression = GetMethodExpression (MemberExpression) be. Object, resultValue, be. Method. Name, subst );
Return expression. Body;
}


At this point, the expression tree transformation can finally be applied in the actual project, which is very helpful for us to dynamically collect query conditions, although this problem has plagued me for more than half a month, however, it was finally solved. Expression conversion is troublesome. If you want to make your expression conversion function more and more powerful, you need to write corresponding solutions for different situations. no perfect solution is the best choice.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.