I have read the following: https://stackoverflow.com/a/20766203/10046099
What I don't get is this part:
Expression trees were created in order to make the task of converting code such as a query expression into a string that can be passed to some other process and executed there. It is that simple.
If we got query expression, why can't it directly transform it into sql string that gets sent to sql database? Why is tree necessary? Because what happens is instead of directly transforming query expression into sql string, it first transforms it into tree and then transforms tree into sql string which means 2 steps instead of 1.
I'd appreciate the easiest explanation.
UPDATE
Let's look at the following linq
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
Could you turn this into expression tree as a binary tree drawing? Maybe after this, it will get easier to me how expression trees then get transformed into sql string.
CodePudding user response:
If we got query expression, why can't it directly transform it into sql string
And what SQL dialect would you use? That would mean the LINQ system would basically have to include all possible SQL dialect generators.
Also you would not be able to generate the expression trees in multiple steps. And yes, this is a thing - generating the first where, then adding where clauses in a long list of if conditions.
By generating an expression tree, you can not only manipulate it before generating the SQL, you can also then have the SQL generation done by an adapter further down. This way you can support every SQL dialect.
CodePudding user response:
The compiler transforms your code into
IEnumerable<int> scoreQuery scores.Where(score => score > 80).Select(score => score);
In a second step, this code is transformed into
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "score");
BinaryExpression body = Expression.GreaterThan(parameterExpression, Expression.Constant(80, typeof(int)));
ParameterExpression[] array = new ParameterExpression[1];
array[0] = parameterExpression;
Expression<Func<int, bool>> whereExpression = Expression.Lambda<Func<int, bool>>(body, array);
parameterExpression = Expression.Parameter(typeof(int), "score");
ParameterExpression body2 = parameterExpression;
ParameterExpression[] array2 = new ParameterExpression[1];
array2[0] = parameterExpression;
Expression<Func<int, int>> selectExpression = Expression.Lambda<Func<int, int>>(body2, array2);
IEnumerable<int> scoreQuery scores.Where(whereExpression).Select(selectExpression);
This is the way how the information that e.g. it should be checked whether score is greater than 80 is stored. Basically, you could write your code directly like above, but it is much more effort and harder to read, that's why the compiler offers the abbreviation from the one-liner above.
During runtime, Entity Framework or any other ORM tool will analyze the expression trees above. It will use the information stored there to build the SQL query. For example, because the NodeType
of the where expression is ExpresionType.GreaterThan
, EF will use a >
in the SQL query.