Sunday, January 29, 2012

C# 3.0 for Beginners - Query Execution in LINQ

The execution of queries written is different from what a new LINQ user would perceive it to be. The query isn’t evaluated and the result is not stored in the query variable until the foreach iteration (where the values are actually required) or a manual iteration using the underlying GetEnumerator and MoveNext methods. The query variable only stores the query commands. This is concept is referred to as deferred execution.
public static void GetIExplorer()
{
    //  1. Data Source
    Process[] processes = Process.GetProcesses();

    //  2. Query Creation
    IEnumerable<int> query =
       from p in processes
       where p.ProcessName.ToLower().Equals("iexplore")
       select p.Id;

    //  3. Query execution
    //  This is the part where the query is evaluated
    //  and result is stored in the query variable.
    foreach (int pid in query)
    {
        Console.WriteLine("Process Id : "+pid);
    }
}

As the query variable doesn’t store the results, you can execute it as many times as you like. If a data source is updated at regular intervals, you could retrieve the latest results every time you iterate over the query variable.


The figure shown above shows information about the query variable ‘query’. The Results View section shows the results of query execution and it also informs the user that “Expanding the Results View will enumerate the IEnumerable” i.e. perform the query execution for debugging.

Forcing immediate execution of queries
Immediate execution of queries is forced for queries that perform aggregation functions over the data retrieved from query evaluation. These functions include Count, Max, Min, Average etc. These queries execute without an explicit foreach statement because the query itself would use a foreach statement to calculate the result.

The following query returns the number of processes identified as “IExplore.exe”.
//  Calculate the number of "iexplore" processes
int numberOfProcesses = query.Count();

Execution results can be cached (if need be) for temporary processing using the ToList() and ToArray() methods as shown below:
//  Caching results using ToList() and ToArray() methods.
List<int> queryResult =
(from p in processes
    where p.ProcessName.ToLower().Equals("iexplore")
    select p.Id).ToList();

Array inferredQueryResult =
    (from p in processes
    where p.ProcessName.ToLower().Equals("iexplore")
    select p.Id).ToArray();


No comments:

Post a Comment