Tuesday 21 June 2016

Language Integrated Query (LINQ) To Objects

Language Integrated Query is an innovation introduced in .Net 3.5 with a vision towards bridging the gap between world of object and world of Data.

Before the LINQ, developers have to learn a different query language. Like for the XML documents dev's have to work  classes like XmlWriter,XmlReader and similarly for the SQL DataBases dev's have to work with SqlConnection,SqlCommand and so on. So Linq removed this difficulty of learning different query language for each DataSet.

We can write LINQ queries in C# for all the available datasets like SQL databases, XML documents, various Web Services  and for any other collection of objects which is implementing the IEnumberable Or IEnumerable<T> interface. See MSDN for the Reference. 

Moving towards the implementation of the LINQ, LINQ offers different flavors.

  • LINQ TO DataSets
  • LINQ TO Entity Framework
  • LINQ to Objects
  • LINQ to XML


Moreover there are two types of writing the LINQ queries.
1. Linq Query Syntax
2. Linq through Extension Methods

In this blog I am only focusing on Linq Query Syntax and not on Linq Through Extension Methods. 

BASIC QUERY OPERATORS:

Before diving into the implementation of the LINQ to objects lets have a look into the LINQ Query operators that are available for different operations. 

There are three different basic steps for writing a LINQ Query. The code samples are just to give an overview of the LINQ operators. 


1. Obtaining a Data Source:

In a LINQ query, the first step is to specify the data source. In C# as in most programming languages a variable must be declared before it can be used. In a LINQ query, the from clause comes first in order to introduce the data source (customers) and the range variable (cust).



The variable "queryAllCustomers" is the result of the above mentioned query and after applying the foreach loop the results can then be extracted. (Discussed Later). The range variable is like the iteration variable in a foreach loop except that no actual iteration occurs in a query expression. When the query is executed, the range variable will serve as a reference to each successive element in customers. Because the compiler can infer the type of cust, you do not have to specify it explicitly

2. Create the Query:
Creating the query includes performing different operations after obtaining the data source. Basic query operations involves the following with examples:


a. Filteration of data
Probably the most common query operation is to apply a filter in the form of a Boolean expression. The filter causes the query to return only those elements for which the expression is true. The result is produced by using the where clause. The filter in effect specifies which elements to exclude from the source sequence. In the following example, only those customers who have an address in London are returned.






You can also apply logical operators in these queries like && and || and it will work just fine as the normal scenarios. For more information please explore "Where Clause" in MSDN. 

b. Ordering:
Often it is convenient to sort the returned data. The orderby clause will cause the elements in the returned sequence to be sorted according to the default comparer for the type being sorted. For example, the following query can be extended to sort the results based on the Name property. Because Name is a string, the default comparer performs an alphabetical sort from A to Z.


If we want to sort the result in the descending order then we just have to replace the ascending with the descending keyword. Intellisense will help you with that.

3. Selecting (Projection) :

The select clause produces the results of the query and specifies the "shape" or type of each returned element. For example, you can specify whether your results will consist of complete Customer objects, just one member, a subset of members, or some completely different result type based on a computation or new object creation.


The select clause in here produces the result and assigns the result to the "queryLondonCustomers3". 
The point to mention here is that if we want to select more than one element/attribute or a set of specific characteristics then a Technique comes in which is know as projection. See the code below:


Notice the "new " keyword here. This new keyword is used to create an anonymous object in here and it will select only the Name and City characteristics of all the customers.

There are other operations like grouping and joining of the Queries but I am not going to discuss that here. Please see MSDN for the reference.



3. Execution of Data:

And at the end We are going to execute the query and for that we are going to use the foreach loop. And it would be done something like this:

Notice we are using foreach loop in here for the execution of query. Reason for that is discussed later. 


LINQ TO OBJECTS:

LINQ To Objects refer to the use of queries for all the collections which implements the IEnumerable or IEnumerable<T> interface like List<T>,List and all other collections including Arrays,Dictionary and so on. 
If you don't know about the IEnumerable<T> or IEnumerable please see the links given at the end. In Fact the Foreach loop in .Net depends completely on IEnumerable. 


Now we have the basic understanding of the Linq queries we are going to apply our above knowledge to the Objects and are going to explore various concepts in this section like Immediate and Deferred Execution. 

  • Create An Console Application in Visual Studio. 
  • Create A Class named Student:




  • Go to the Main.cs and Create a List of the Student and populate that list with the dummy data for just applying the queries. 





  •  Now from here we are going to apply the LINQ Query Operators to retrieve the results. If we don't have these operators we will be prompted to manually search through the List by using conditional statements but LINQ simplifies this hurdle. In first step I am going to obtain the data source and retrieve all the students. 



 The output will be the following as expected: 



That's the power of the LINQ which just writing 2 lines of code we are having all the related data we wanted and same will be the case with all the datasets that are available. 


  •  Now Applying filters. Let's say we have want to retrieve a student which belongs to the city "Sialkot" so for that we are going to use the where clause. 



The result we will be having will be :





5. Now we are going to sort the students according to the names of the students and you can then sort accordingly to your own requirements. So let's have an example:

And the output will be then be as follows:







Sorting depends upon the default comparer as implemented. If you are willing to implement the default comparer in your own implemented classes then see the IComparer and IComparable Interface. 


  •  Now Finally we are going to talk on Projection or selecting the data. you have seen above the select clause which is just selecting the whole instance of the student and you get all of the information of the student. But let's say we are not interested in the whole information and we want to just have the Name of the students. So what's we going to do that? Here's the concept comes which is known as the Projection and that is achieved through the help of anonymous types. See the code: 






Now we are using the "New " keyword here and using the anonymous types here to select specific data of the student is known as the projection. We can the following results:



Now instead of having the whole instances of the class we just have the Name and the fathers Name of the students. See MSDN for the reference ( Anonymous types) .

So this is how the LINQ eases the way to retrieve the results from the objects and just by learning some operators we can apply on different datasets easily. Either that is XML or SQL or any.



Immediate Execution and Deferred Execution:

Now as you will notice in above all of the scenarios, that we are using foreach loop every time. The reason for this is that the LINQ query will be executed when we will apply foreach loop over the selected results. For supporting my argument I am going to Add a new student in the class after applying query but before applying foreach Loop and you will see the required results. 

Notice that we have added a new student after the query. As a general perception you will be thinking that the student with the name Noman will not be included in the results. But let's see the results. 




Notice the name Noman is included. That's called Deferred Execution. which means the LINQ query will not be implemented unless we apply foreach loop over that. We can also see by putting break point in there. And after pressing F11 "Step into debugging" and the control will again go into the query and will then output the result. 


Now let's see what is immediate execution. Immediate execution doesn't waits for the foreach loop to get executed. Queries that returns a singleton value like Average,Sum and count are implemented before the foreach loop. Lets see through the example. 



This code sample is converting the results into List. And we are again adding the student before showing onto the console. And the result will be;



There should be 11 students. But this is showing that the query is executed before the foreach loop and instead of adding the 11th student in the list, the result is only of 10 students. 

So this is how immediate execution differs from the deferred execution and it can have adverse effects in the enterprise applications. 

Now you have learn the basics of the Linq you should explore other features of LINQ like joining and grouping. And Applying LINQ To SQL and other DataSets should not be a big problem for you.

7 comments: