-2

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.

SomeBody
  • 7,515
  • 2
  • 17
  • 33
Nika Kurashvili
  • 6,006
  • 8
  • 57
  • 123
  • 3
    "If we got query expression, why can't it directly transform it into sql string that gets sent to sql database ?" - what is the "it" that you expect to do this? The C# compiler sees the lambda expression as source code, but it would be a horrible violation of separation of concerns for the C# compiler to have to know about SQL. (What about things other than SQL, which can be handled using the current architecture? Would you propose that *everything* gets bundled in the C# compiler? What if you want to support a query language that the C# compiler team doesn't like?) – Jon Skeet Nov 05 '21 at 12:42
  • *which means 2 steps instead of 1* - I'm kinda curious why you see it as a bad thing. After all, when you write C#, the CPU doesn't *run* C#.. It will be transformed *many* times before it's a bunch of 0s and 1s/voltage levels so you must appreciate that having intermediary steps is really handy for all sorts of reasons all through your life - it's not just Intel vs ARM CPUs or WIndows vs Linux.. Showing your workings in math exam at least lets you get some points even if the result was wrong. Iron ore smelting plants don't make cars. Direct from A to Z is generally quite a bad idea overall – Caius Jard Nov 05 '21 at 12:54
  • The statement you posted is not a LINQ Expression. It contains two LINQ Expressions: `score > 80` and `score`. – Ian Mercer Nov 05 '21 at 12:54
  • @IanMercer I am trying to understand if Linq gets transformed into expression tree, how does expression tree know how to transform it into specific sql database ? it could be sql, postgresql, mysql or whatever which might have different syntax in the end. ? – Nika Kurashvili Nov 05 '21 at 12:55
  • Why do you think the expression tree itself knows how to transform itself into TSQL/PLSQL/xSQL? – Caius Jard Nov 05 '21 at 12:57
  • Expression tree doesn't know anything about sql, but specific database provider does. If you feed the same expression to multiple database providers - they might produce different sql. – Evk Nov 05 '21 at 12:57
  • A LINQ Provider converts the expression tree into whatever form the database (or other data source) needs to execute the query. You can use expressions with non-SQL databases, with in-memory object queries, ... See https://learn.microsoft.com/en-us/previous-versions/bb546158(v=vs.140) and other articles on LINQ Providers. – Ian Mercer Nov 05 '21 at 12:58
  • so in the end, in C# , you use providers to transform data into specific sql string. why not use providers so that providers transform Linq queries into specific sql strings ? – Nika Kurashvili Nov 05 '21 at 12:58
  • it seems like providers can more easily transform expression tree into sql string than providers can transform direct Linq expression into sql string. no idea why – Nika Kurashvili Nov 05 '21 at 13:06
  • 1
    I'd usually recommend if you don't see a use for a feature, just put it in your "might be interesting, but not relevant to me now" pile. Later, if you have a problem and someone offers you a solution that uses the feature, you will have a *real*, compelling, relevant to *you* reason for why it's useful. And you don't need to ask others to justify the existence of the feature in the meantime. Perhaps it'll never be relevant to you - that's okay too. – Damien_The_Unbeliever Nov 05 '21 at 15:18
  • @IanMercer Not that it's super relevant to the question, but the OP's code results in a single call to a single LINQ method with a single expression. Since the select is an identify select it is elided in this situation. – Servy Nov 05 '21 at 15:23

2 Answers2

0

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.

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • It caused more confusion and that's why. Generally I end up on this : it seems like providers can more easily transform expression tree into sql string than providers can transform direct Linq expression into sql string. no idea why. Sorry again – Nika Kurashvili Nov 05 '21 at 13:08
0

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.

SomeBody
  • 7,515
  • 2
  • 17
  • 33