Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / HPC / parallel-processing

Linq DLinq XLinq PLinq All at one place

4.64/5 (24 votes)
27 Aug 2010CPOL8 min read 43.1K   1.1K  
Overview of Linq for beginners

Introduction

Yes, I know there are many articles on the internet on this topic and many are on CodeProject itself. However, the thing that I found missing was a single place where a newbie could get all the related information about LINQ. Later, one can drill down on the topics of his/her interest.

Through this article, I am trying to share information about this one of the salient feature of the .NET. I am looking forward to enable a beginner to write the code in the LINQ way if he is not doing that already. Also I hope to make one start thinking of the solutions in the same direction. Of course, this doesn't provide all the details about the topic. This article gives you the cursors and general understanding about LINQ.

What is LINQ

LINQ stands for the Language Integrated Query. It relies on the language improvements (C# 3.0 and VB 9.0 onwards).

This is what Microsoft says about LINQ:

"LINQ is a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. It extends C# and Visual Basic with native language syntax for queries and provides class libraries to take advantage of these capabilities." In simple terms, LINQ is something you can use for writing the queries that fits your needs and operates against various data stores including remote one, e.g. SQL, etc.

Why Use LINQ

In general programming scenarios, we queries various kinds of data stores, e.g., object collections, database and XML, etc. For querying these data stores, we have got to use different mechanisms that are best suited for them. For example, we use foreach loop for querying the collection, write SQL queries for database and Xpath queries for querying the XML data.

So the point here is that we need to know individual terminology for doing similar things when we got to work with different data stores. To make my point more clear, consider the scenario where we need to find the customers from the specific region (say India).

Query using object:

C#
foreach(Customer c in customers) 
if (c.Region == "India") … 

Query from database table:

C#
SELECT * FROM Customers WHERE Region='India'

Query XML using xPath:

XML
//Customers/Customer[@Region=‘India'] 

What LINQ tries to do here is that it provides you the UNIFORM APPROACH for querying and manipulating the different data sources. Therefore, for querying the data, you do not need to learn XPath, SQL and Object iterations. All you need to know is how to query using LINQ. Once you start using it in your day to day applications, you will realize the real power of it.

Moreover, LINQ comes with some perks which are as follows:

  • Bridges the gap between OO and Relational data
  • Integrated directly in the language
  • Type checking and compile time safety
  • Intellisense
  • Debugger support

Sample LINQ Query and Its Dissection

A simple Linq query looks similar to the one as follows:

C#
var contacts = from c in customers
where c.Region == "India"
select new {c.Name, c.Phone}

This small code fragment contains few of the language features supported by the 3.0 framework onwards which are identified in the following illustration. Both the queries are the same, it's just the notation that is changed.

sampleq.PNG

Following are the terms that have popped up from a simple LINQ query.

1) Standard Query Expression

These are the language syntax which are there to assist you writing the LINQ queries that are understood by the .NET Framework.

qexp.png

2) Local Variable Type Inference

This allows you to use var instead of explicitly specifying the type. Linq queries usually return IEnumerable<T>. In some cases, it's convenient to use the anonymous types. Point to notice here is that the variable deduces the variable type from the initializer. Scope of the var is always local.

C#
int i = 666;
string s = "Goodbye";
double d = 3.14;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int,Order> orders = new Dictionary<int,Order>();

could be replaced by the following:

C#
var i = 666;
var s = "Goodbye";
var d = 3.14;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();

3) Object Initializers

This allows you to create an instance of an object in just one line by providing the values for the properties:

C#
public class Point
{
    private int x, y;
    public int X { get { return x; } set { x = value; } }
    public int Y { get { return y; } set { y = value; } }
}

The following line creates an instance of Point object with the parameters provided.

C#
Point a = new Point { X = 0, Y = 1 };

4) Anonymous Types

Usually we create the types with some name. This feature allows you to create the type that does not have any name.

C#
var i1 = new {CustomerId = 123, Name = "santosh" };
var i2 = new {123, "santosh"};

5) Lambda Expressions

Definition:
A lambda expression is an anonymous function that can contain expressions and statements.

Let's see how the Lambda expression get evolved. Let's say we want to get the customers which have the City as "London". To do this, one can use one of our old traditional friends named delegate.

  1. Getting the customers using delegate:
    C#
    List<Customer> customers = GetCustomers();
    var local = customers.FindAll(CityEqualsLondon);
    private bool CityEqualsLondon(Customer c){
                return c.City == "London";
    }
  2. Let's say you do not want to create a function, e.g., CityEqualsLondon() that does the filtering stuff, you can use the anonymous method instead. It's just inline and you get the desired result.
    C#
    List<Customer> customers = GetCustomers();
    var local = customers.FindAll(delegate(Customer c) { return c.City == "London"; });
  3. Why not have something that does the required thing without writing some common syntax that the compiler can anyway find out by looking at the code. The solution that came out was lambda expressions.
    C#
    List<Customer> customers = GetCustomers();
    var local = customers.FindAll(c => c.City == "London");

So the c => c.city == "London" is a lambda expression that contains all the required information to give to compiler so the compiler knows what to do. "=>" is read as "goes to".

Following are two terms that you should better be knowing when using the LINQ or Lambda expressions.

Predicate

C#
(p) => p.Gender == "F" 
//All persons, p, such that person’s Gender is "F" 

Projection

C#
(p) => p.Gender ? "F" : "Female" 
//"Each person p becomes string "Female" if Gender is "F 

6) Extension Methods

This feature lets you add methods to the existing types without creating the derived type.
Following are the items that explains the Extension Methods.

  • Extends Existing Types
  • Adds Methods Without Derivation
  • Accesses Public Members of Extended Types
  • Must be:
    • public and static
    • Housed within a static class
  • Use this keyword before parameter of extended type

Following is the code to create a sample extension method named ToMsgbox that extends the strings array in such way that the strings gets concatenated with new lines and gets displayed in a message box. It's not a very good example, however, fair enough to explain the basic idea behind this.

C#
public static class MyExtns
   {
       public static void ToMsgbox(this string[] strings)
       {
           MessageBox.Show(string.Join(Environment.NewLine, strings));
       }
   }

LINQ Architecture

The following figure explains the basic architecture of the LINQ. You write the LINQ queries in the language of your choice that operates on the LINQ enabled data sources. There are basically three main logical branches for the LINQ. LINQ to Object, LINQ to Database and Entities (known as DLINQ) and LINQ to XML (known as XLINQ).

arch.PNG

LINQ to Objects

LINQ to Objects sample:

C#
string[] testStrings = { "Santosh", "Vikram", "Mohit", "Chirag", 
"Amit", "Vikas", "Vipul", "Andy" };
            
            var temp = from str in testStrings
                       let words = str.ToLower().ToCharArray()
                       where str.Length > 4 && words[0] == 'v'
                       orderby str.Length descending
                       select str;
            temp.ToArray().ToMsg();

LINQ to SQL/Entities (DLINQ)

When you query the database and entities using the LINQ queries, it's referred as DLINQ. Visual Studio provides you the option to do the OR mapping in the integrated designer. You can check out more details from one of the ScottGu's blog here.

Here are some points to note about DLINQ:

  • ORM Designer Maps Relational Structures to Classes
  • Pushes query processing from in-memory to a remote data store
  • Automatically generates parameterized SQL
  • Fully supports stored procedures
  • Tables have CRUD definitions (Default = use runtime)
    • Can instead point to stored procedures
  • Built on the concept of Deferred Loading

The following figure explains how the LINQ to SQL works:

linq2sql.PNG

Following is the sample code snippet to explain the deferred execution. You see, the actual query is triggered to the database when DataBind() is executed. So the execution of actual query keeps on getting deferred up to the time till there is no other option. Most query operators don’t execute when declared.

C#
//Define query 
var query = from c in ctx.Customers 
where c.Region == "India" 
select c; 

//Execute query 
gridViewCustomers.DataSource = query; 
gridViewCustomers.DataBind(); //Execute here 

In addition to this,

  • Query gets executed when enumerated
  • Bound to a DataBound control
  • Execute within ForEach loop Iteration
  • Transformed to collection ToList(), ToArray(), etc.

Deferred Execution

  • Benefits:
    • Fetches data only when needed, not all at once
    • Minimize network traffic, memory consumption and load on database
    • Great for when can but fetch objects as user requests them
  • Drawbacks:
    • Chatty Interface: Each request for child record invokes explicit database query

Immediate Execution

  • Benefits:
    • Singe query returns all data
    • Great if you know that you will need all data returned
  • Drawbacks:
    • Large amount of data returned, whether used or not

Here is what an ORM designer look like:

nwind.PNG

Here come a few sample DLINQ queries:

Select products

C#
var products = from p in _NWindDataContext.Products
where p.CategoryID == 1
select new { p.ProductName, p.CategoryID };
C#
dataGridView1.DataSource = products; 

Insert a product

C#
Product product = new Product();
product.CategoryID = 1;
product.ProductName = "testProduct";
_NWindDataContext.Products.InsertOnSubmit(product);
_NWindDataContext.SubmitChanges();
RefreshData();

Update Product

C#
var product = (from p in _NWindDataContext.Products
where p.CategoryID == 1 && p.ProductName.Contains("testProduct")
select p).First();
product.ProductName = "santosh";
_NWindDataContext.SubmitChanges();
RefreshData();

Delete Product

C#
var product = (from p in _NWindDataContext.Products
     where p.CategoryID == 1 && p.ProductName.Contains("santosh")
     select p).First();
_NWindDataContext.Products.DeleteOnSubmit(product);
_NWindDataContext.SubmitChanges();
RefreshData();

LINQ to XML (XLINQ)

Is simple words, when you write your LINQ queries that operates on the XML, they are referred as XLINQ queries.

C#
XDocument xdoc = XDocument.Load("auths.xml");
var auths = from a in xdoc.Root.Descendants("author")
                       where a.Element("au_fname").Value.Contains("a")
                       orderby a.Element("au_fname").Value.Length descending
                       select a.Element("au_fname").Value;

Expression Tree

Expression trees represent code in a tree-like data structure, where each node is an expression. You can create an expression tree of lambda expressions that are quite useful when you query using LINQ and there are many conditional filters (where clauses) you want to apply on the query.

C#
public delegate bool Predicate<T>(T item);

Expression<Predicate<Customer>> test = c => c.Region== "India";

ParameterExpression c = Expression.Parameter(typeof(Customer), "c");
Expression expr = Expression.Equal(
        Expression.Property(c, typeof(Customer).GetProperty("Region")),
        Expression.Constant("India")
    );

Expression<Predicate<Customer>> test =
    Expression.Lambda<Predicate<Customer>>(expr, c);

Parallel LINQ - (PLINQ)

Framework 4.0 introduces parallel processing. LINQ also got its share by letting the LINQ query run in parallel. How the query gets executed in parallel is a complicated process. I do not want to burden you with more details about this. Please find the link at the end of this article, in case you want to have more details.

plinq.PNG

From the programming perspective, if you want to know how to write a LINQ query that takes advantage of this feature, please refer to the following code snippet and notice the AsParallel():

C#
//LINQ to Object Query
int[] output = arr
    .Select(x => Test(x))
    .ToArray();

//PLinq Query
int[] output = arr.AsParallel()
    .Select(x => Test(x))
    .ToArray(); 

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)