Introduction to Language Integrated Query (LINQ)

Welcome to this installment of the .NET Nuts & Bolts column. The focus of this article will be an introduction to Language Integrated Query, or LINQ for short. This article will cover what LINQ is and isn’t, with a brief refresher on the language features that enable it, and then jump in to some examples of working with LINQ. This will be part one of a couple of articles that cover LINQ in some detail.

What is Language INtegrated Query?

Many of the past .NET Nuts & Bolts columns, even all the way back to some of my first articles such as Database Independent Data Access, have had something to do with accessing and manipulating data. Commonly, data is stored in a database, but there are many other forms of accessing and manipulating data as well such as data files, event logs, the Registry, and so forth. Querying and manipulating data is a common part of many applications.

LINQ (often overheard pronounced as “link”) is a step in the evolution of data access. It is a programming model that brings a much needed uniformity to accessing data from files, XML, database, registry, event log, and a whole host of other sources of data such as Active Directory and even services from 3rd parties such as Flickr. It is designed to work with all shapes and sizes of different data and allow you to perform Query, Set, and Transform operations on all of it. Pretty much anything that implements IEnumerable is a target for LINQ.

What Is LINQ Not?

It can be just as useful when trying to understand something to look at the counter of what it is, which is what it is not. One of the most common reactions I’ve heard about when people are first introduced to LINQ is that it is just embedded SQL, which it is not. Although LINQ syntax can be SQL-like in many of its forms, it is not just embedded SQL and is not limited to just querying databases. LINQ is not automatically supported by all .NET languages. There were no modifications to the Common Language Runtime (CLR). All of the modifications were made to the languages and their respective compilers. It requires some language-specific extensions. Visual Basic .NET 9.0 and C# 3.0 both have integrated language support for LINQ.

Language Features that Enable LINQ

LINQ makes heavy use of Generics. Additionally, there were a number of features added to the Visual Basic and C# languages specifically to support LINQ. A couple of my more recent articles introduced some of these language features as a precursor to LINQ. The following contains a partial list of the language features that help enable LINQ and a brief description of each:

  • Type inference: Shorthand indicating the variables type is the compile time type of the right hand assignment
  • Extension Methods: Extending an existing value or reference type without deriving a new type
  • Object initializer: Short form of object initialization syntax that generates the equivalent code
  • Anonymous types: Create statements without constructing a method or type
  • Lambda expressions: Concise way of creating inline methods
  • Query expressions: SQL-like statements within code for manipulating objects

I’m certain each of these languages features adds some benefit on their own, but I’ve not personally found reason yet to use many of them outside of LINQ.

Flavors of LINQ

There are a variety of flavors of LINQ for accessing and manipulating different data sources. The trailing list contains some of the data domains provided by Microsoft. Some of these will be topics of future .NET Nuts and Bolts articles.

  • LINQ to Objects: Manipulates collections of objects
  • LINQ to DataSets: Manipulates a DataSet using LINQ
  • LINQ to SQL: Maps between custom types and a physical database table schema
  • LINQ to Entities: Uses a conceptual Entity Data Model to create a conceptual model of a physical database
  • LINQ to XML: Allows querying and manipulation of XML

Introduction to LINQ Syntax

For those who are very particular about how their code is structured and formatted, it is likely to take a little bit to get comfortable with LINQ syntax and having it sit in your code. For those whi have routinely heard the mantra not to embed SQL queries within your code, it will take a bit to get comfortable that you are not indeed doing anything wrong or dirty by using LINQ, but rather quite the opposite.

Even though LINQ absolutely is not limited just to accessing databases, I have found it of value in helping people to understand LINQ to first examine a SQL statement and then introducing the in-code LINQ representation of the same thing. The following SQL statement is one constructed against the Northwind sample database common to Microsoft SQL Server. The query is pretty basic and simply pulls a list of customers that are not located in the city of Berlin.

SELECT c.CompanyName, c.ContactName, c.City
FROM Customers c
WHERE c.City != 'Berlin'
ORDER BY c.ContactName

Now, look at a LINQ representation of the same thing and dissect it to understand the pieces and parts. There are two different types of query syntaxes: query expressions and method queries. You’ll focus on query expressions for now. The following query expression would search the IEnumerable type returned from GetCustomers() and find those that did not have a City location of Berlin. For this example, you’ll assume the GetCustomers method accesses the database and returns an IEnumerable type.

var customerNotInBerlin =
   from c in GetCustomers()
   where c.City != "Berlin"
   orderby c.ContactName
   select c;

The following table outlines some of the options available with LINQ syntax.

Destination var <variable> = Using type inference to assign the resulting value(s)
Source from <item> in <data source> Information source providing a set of item(s)
Filter where <expression>, distinct Expression specifying the selection criteria
Order order by <expression>, <expression> [Ascending | Descending] Control the ordering of the results
Aggregate count([<expression>]), sum(<expression>), min(<expression>), max(<expression>), avg(<expression>) Aggregate the source items
Projection select <expression> Shaping the output

There are many more options and variations of syntax than what is provided above, but this should give you a starting point for familiarity.

Test Driving LINQ Through Examples

Now that you’ve covered a little of the background, take LINQ for a test drive through a few handy examples. You’ll look at how to use LINQ to read data from a structured type, a file, and an example that involves using LINQ to access the EventLog.

Accessing a Structured Type

You’ll build on the example you were using earlier to show the syntax and query a structured type. You’ll create a Customer structured type and type in some data from the Northwind database to fill your Customer structured type. You’ll select all of the records where the City is not Berlin and then display them to the console. Because you’re selecting Customer objects, the ToString method you’ll add to your Customer will be used to display a comma-delimited list of attributes.

using System;
using System.Collections.Generic;
using System.Linq;

namespace LINQIntro
   class Customer
      public string CustomerName { get; set; }
      public string ContactName { get; set; }
      public string City { get; set; }
      public override string ToString()
         return this.CustomerName + ", " +
            this.ContactName + ", " + this.City;

   class Program
      static void Main(string[] args)

      public static void ShowCustomers()
         // Build a list of customers using an object initializer
         List<Customer> customers = new List<Customer> {
            new Customer { CustomerName = "Alfreds Futterkiste",
               ContactName = "Maria Anders", City = "Berlin"},
            new Customer { CustomerName =
               "Ana Trujillo Emparedados y helados",
               ContactName = "Ana Trujillo",
               City = "México D.F."},
            new Customer { CustomerName =
               "Antonio Moreno Taquería",
               ContactName = "Antonio Moreno",
               City = "México D.F."},
            new Customer { CustomerName = "Around the Horn",
               ContactName = "Thomas Hardy",
               City = "London"},
            new Customer { CustomerName = "Berglunds snabbköp",
               ContactName = "Christina Berglund",
               City = "Luleå"}};

          // Query the list of customers and select whatever
          // comes back
         var customer =
            from c in customers
            where c.City != "Berlin"
            orderby c.ContactName
            select c;

         // Display the selected records to the console
         foreach (var row in customer)

More by Author

Must Read