Let me start by saying that if you compile your query or not, it does not matter. You will observe the same results, even if you have not precompiled.
Technically, as Andrew noted, making this work not so difficult. When a LINQ expression is evaluated, an expression tree is created internally. Your function is displayed as a node in this expression tree. There is no magic here. You can write this expression in both L2S and L2E, and it will compile and work fine. This is until you try to actually execute the actual SQL query against the database. This is where the difference begins. L2S seems to happily perform this task, while L2E fails with a NotSupportedException and reports that it does not know how to convert ToThema into a storage request.
So what's going on inside? In L2S, as Andrew explained, the query compiler understands that your function can be run separately from the storage request. Thus, it issues calls to your function in the object read pipeline (where the data read from SQL is converted to objects that are returned as a result of your call).
Once Andrew’s thing wasn’t quite right, what's important is what's inside your static method. I do not think so.
If you put a breakpoint in the debugger for your function, you will see that it is called once for each returned line. In the stack trace, you will see the “Easy Function”, which actually means that the method was emitted at runtime. So this is how it works for Linq to Sql.
The Linq to Entity team seemed to be on a different route. I don’t know what were the reasons why they decided to ban all InvocationExpressions from L2E requests. It may have been performance considerations, or it could be the fact that they need to support all providers, not just SQL Server, so that data readers can behave differently. Or they simply thought that most people do not understand that some of them are executed for the returned row and prefer to close this option.
Just my thoughts. If anyone has a deeper understanding, please call!
source share