Home > Software design >  What's the usecase of expression tree?
What's the usecase of expression tree?

Time:11-05

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.

  • Related