Tuesday 18 October 2011

Query Execution in LinQ


In LINQ, queries have two different behaviors of execution: immediate and deferred. In this article, we will take a quick overview of how Deferred query execution and Immediate Query Execution works in LINQ
Deferred Query Execution
To understand Deferred Query Execution, let’s take the following example which declares some Employees and then queries all employees with Age > 28:

class Employee

{

public int ID { get; set; }

public string Name { get; set; }

public int Age { get; set; }

}

static void main(string[] args)
{
var empList = new List<Employee>(
new Employee[]
{
new Employee{ID=1, Name=“Himanshu”, Age=“30″},
new Employee{ID=2, Name=“Rahul”, Age=“35″},
new Employee{ID=3, Name=“Hetal”, Age=“26″},
new Employee{ID=4, Name=“Varsha”, Age=“28″},
});
var lst = from e in empList
where e.Age > 28 //<= query seems to be executed here
select new { e.Name };
foreach (var emp in lst)
Console.WriteLine(emp.Name);
Console.ReadLine();
}
OUTPUT: Himanshu, Rahul
Looking at the query shown above, it appears that the query is executed at the point where the arrow is pointing towards. However that’s not true. The query is actually executed when the query variable is iterated over, not when the query variable is created. This is called deferred execution.
Now how do we prove that the query was not executed when the query variable was created? It’s simple. Just create another Employee instance after the query variable is created
static void main(string[] args)
{
var empList = new List<Employee>(
new Employee[]
{
new Employee{ID=1, Name=“Himanshu”, Age=“30″},
new Employee{ID=2, Name=“Rahul”, Age=“35″},
new Employee{ID=3, Name=“Hetal”, Age=“26″},
new Employee{ID=4, Name=“Varsha”, Age=“28″},
});
var lst = from e in empList
where e.Age > 28 //<= query Variable
select new { e.Name };
empList.Add(new Employee { ID = 5, Name = “Tarun”, Age = “39″ }); //<= New employee initialization
foreach (var emp in lst)
Console.WriteLine(emp.Name);
Console.ReadLine();
}
Notice we are creating a new Employee instance after the query variable is created. Now had the query been executed when the query variable is created, the results would be the same as the one we got earlier, i.e. only two employees would meet the criteria of Age > 28. However the output is not the same
OUTPUT: Himanshu, Rahul, Tarun.
What just happened is that the execution of the query was deferred until the query variable was iterated over in a foreach loop. This allows you to execute a query as frequently as you want to, like fetching the latest information from a database that is being updated frequently by other applications. You will always get the latest information from the database in this case.

Immediate Query Execution
You can also force a query to execute immediately, which is useful for caching query results. Let us say we want to display a count of the number of employees that match a criteria.
static void main(string[] args)
{
var empList = new List<Employee>(
new Employee[]
{
new Employee{ID=1, Name=“Himanshu”, Age=“30″},
new Employee{ID=2, Name=“Rahul”, Age=“35″},
new Employee{ID=3, Name=“Hetal”, Age=“26″},
new Employee{ID=4, Name=“Varsha”, Age=“28″},
});
var lst = (from e in empList
where e.Age > 28
select e).Count(); //<= Immediate Execution
empList.Add(new Employee { ID = 5, Name = “Tarun”, Age = “39″ });
Console.WriteLine(“Total employees whose age is > 28 are {0}”, lst);
Console.ReadLine();
}
In the query shown above, it order to count the elements that match the condition, the query must be executed, and this is done automatically when Count( ) is called. So adding a new employee instance after the query variable declaration does not have any effect here, as the query is already executed. The output will be 2, instead of 3.
The basic difference between a Deferred execution vs Immediate execution is that Deferred execution of queries produce a sequence of values, whereas Immediate execution of queries return a singleton value and is executed immediately. Examples are using Count(), Average(), Max() etc.

No comments:

Post a Comment