1. About.com
  2. Computing & Technology
  3. C / C++ / C#

Discuss in my forum

Introducing LINQ with Query and Lambda syntax

By , About.com Guide

This is the third LINQ Tutorial. If you missed the first two, here are links to them.

So What is LINQ? At it's simplest it's a way of doing queries on lists of objects, or XML or objects from a database. At it's more complicated those queries can involve grouping, joining between two different lists or obtaining a restricted subsets of that data and all of it type safe. A really good analogy is a SQL query on a relational Database and overall it's very similar in what you can do and the syntax.

A lot of coding is about manipulating data stored in some kind of list. LINQ simplifies this enormously, making your code more robust in the process. For example no more for loop boundary condition errors,

In a Relational Database

The most common SQL is select something from a table. You can filter the number of rows returned using a where clause. You can also group the data for example to find how many there are of a particular item type and instead of returning every column, you can return just those you need. In addition you can do a complicated join between two or more tables. LINQ lets you do all these things on lists of objects, XML etc.

LINQ offers two syntaxes.

Which you use is a matter of choice though in a few situations, only one can be used. The standard query syntax looks like backwards sql. Here's an example.

Imagine I gave you a list of words and asked you to output all those that are six characters or shorter in order of length of the words. One LINQ query does that

using System;
using System.Linq;

namespace qnil
{
   class Program
    {
    static void Main(string[] args)
     {
     string[] words = {"syntax", "compiler", "integer", "int","C#"};
       var query =
        from w in words
      where (w.Length <= 6)
      orderby w.Length
      select "Word = "+w;
      foreach(var q in query)
        Console.WriteLine(q) ;
    Console.ReadKey() ;
    }
  }
}

The result is

Word = C#
Word = int
Word = syntax

The LINQ query is

var query = from w in words where (w.Length <= 6) orderby w.Length select "Word = "+w;

This builds a list of Word = results. Most LINQ queries of this nature start with a from and end in select. Splitting them over lines makes them easier to read. Let's look at the different parts of this LINQ query.

from w in words. This is like a foreach clause (var w in words). In that case var declares a variable and we want to get one from the words list. w is the current element extracted from the words list.

where (w.Length <= 6). Where is the equivalent of an if statement. It's the same as in sql. This tells LINQ to extract only those words from the list that are 6 characters or fewer in length.

orderby w.Length. Again sql users will recognise order by as sorting the list based on the length of the word. By default this is in ascending order so shortest word first.

Lambda Syntax

This is more powerful but not quite as easy to understand. The above query in Lambda syntax looks like this:

var query = words.Where(w => w.Length <= 6).OrderBy(w => w.Length).Select(w=>"Word = " + w);

These are methods on IEnumerable, so reading left to right the Where method returns a subset of words, these are sorted by OrderBy and then output via Select. Why would you use Lambda Syntax when query syntax is more intuitive?

Because Lambda syntax is more powerful and provides many more commands. Take OrderBy for example. In Lambda queries you can use OrderByDescending and Reverse. In Query syntax you can add the word descending as in

orderby w.Length descending

Which shows the longest word first and so on down to the shortest.

Limitations of Query Syntax

These words are the ones available for use in query syntax.

where, select, orderby, group, join, let, into, from

Where the number of methods for IEnumerable is quite considerable and we'll look at those in the next LINQ tutorial. However let's look at some of the query words above.

Let

Let allows a variable in the query, The earlier example with the words can be rewritten using let to store the value of the word length in the variable l.

var query =
    from w in words
    let l = w.Length
    where (l<= 6)
    orderby l
    select "Word = "+w;

Join

This is very much like the sql join and indeed uses the on keyword as well. It takes two sequences and does a match on a common element.

Using these two lists of pupils and courses.

class Course
{
    public int Age { get;set;}
    public int CourseID { get; set; }
    public string Title {get; set; }
}

class Pupil
{
    public int Age { get;set;}
    public string Name {get; set; }
}

var courses = new List
{
     new Course{Age=15,CourseID = 1, Title="New Romantics"},
     new Course{Age=18,CourseID = 2, Title = "Advanced Algorithms"},
     new Course{Age=19,CourseID = 3, Title = "Thorium Reactors 101"},
     new Course{Age=15,CourseID = 4, Title = "Hacking for Teenagers"},
     new Course{Age=18,CourseID = 5, Title = "Weaponizing Robots"}
};
var pupils = new List
{
     new Pupil{Age=13,Name="Alfredo Marks"},
     new Pupil{Age=18,Name="Benjamin Button"},
     new Pupil{Age=15,Name="Cyan O'Gen"},
     new Pupil{Age=18,Name="James Tiberius Kirk"},
};

We can construct a simple where between them.

var query =
  from c in courses
  from p in pupils
  where p.Age==c.Age
  select p.Name + " On Course (ID="+c.CourseID+
   ") "+c.Title;

or using the join keyword

var query =
  from c in courses
  join p in pupils on c.Age equals p.Age
  select p.Name + " On Course (ID="+c.CourseID+
   ") "+c.Title;

Both return the course placements below. Alfredo is left out!

Cyan O'Gen On Course (ID=1) New Romantics
Benjamin Button On Course (ID=2) Advanced Algorithms
James Tiberius Kirk On Course (ID=2) Advanced Algorithms
Cyan O'Gen On Course (ID=4) Hacking for Teenagers
Benjamin Button On Course (ID=5) Weaponizing Robots
James Tiberius Kirk On Course (ID=5) Weaponizing Robots

Notes:Join can be a bit fussy. for instance c.Age equals p.Age but not the other way round without making it from p in pupils join c in courses. The equals keyword must be used, if you try = it will fail "Expected contextual keyword 'equals'".

We'll look at Group and Into in the next LINQ tutorial.

©2012 About.com. All rights reserved. 

A part of The New York Times Company.