Deferred execution in Linq pitfall(s)
Say you have this query in Linq to Sql
// C# int id = 10254; var q = from o in nw.Orders where o.OrderID = id select o; // some other code id++; foreach(var o in q) { // process o. }
What order is fetched: 10254 or 10255? That's right, 10255! The 'id' used in the query is added as a member access node to the expression tree. As Linq expression trees are converted to Sql when they're executed, it means that at that time, the value of id is evaluated and used inside the query.
So I then wondered, what if 'id' is a local variable in a method which creates the query while the query is executed outside the method? That would mean the query holds a reference to a member which doesn't exist anymore in theory, as 'id' is allocated in the stackframe of the method.
// C# IQueryable q = Foo(); foreach(var o in q) { // process o } //... private IQueryable Foo() { NorthwindDataContext nw = new NorthwindDataContext(); int id = 10254; var q = from o in nw.Orders where o.OrderID = id select o; return q; }
As 'id' is inaccessable from outside the method Foo, I can't increase it. However the query does result in a normal query, where the order 10254 is fetched. To me, this is a little odd, as 'id' isn't known at the time of execution of q, as Foo's stackframe has been cleaned up. We've seen in our previous test that 'id's value isn't inserted into the query, but the reference to the variable. This either is a low-level CLR trick, or something fishy with stackframes which are already cleaned up. Am I overlooking something here or is this indeed strange? (the expression tree refers to a weird type (c__displayClass0) )....