Basic LINQ Query Operations (C#)

This topic gives a brief introduction to LINQ query expressions and some of the typical kinds of operations that you perform in a query. More detailed information is in the following topics:

LINQ Query Expressions (C# Programming Guide)

Standard Query Operators Overview

Walkthrough: Writing Queries in C# (LINQ)

Note

If you already are familiar with a query language such as SQL or XQuery, you can skip most of this topic. Read about the "from clause" in the next section to learn about the order of clauses in LINQ query expressions.

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).

//queryAllCustomers is an IEnumerable<Customer> 
var queryAllCustomers = from cust in customers
                        select cust;

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. Additional range variables can be introduced by a let clause. For more information, see let clause (C# Reference).

Note

For non-generic data sources such as ArrayList, the range variable must be explicitly typed. For more information, see How to: Query an ArrayList with LINQ and from clause (C# Reference).

Filtering

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.

var queryLondonCustomers = from cust in customers
                           where cust.City == "London" 
                           select cust;

You can use the familiar C# logical AND and OR operators to apply as many filter expressions as necessary in the where clause. For example, to return only customers from "London" AND whose name is "Devon" you would write the following code:

where cust.City=="London" && cust.Name == "Devon"

To return customers from London or Paris, you would write the following code:

where cust.City == "London" || cust.City == "Paris"

For more information, see where clause (C# Reference).

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.

var queryLondonCustomers3 = 
    from cust in customers
    where cust.City == "London" 
    orderby cust.Name ascending 
    select cust;

To order the results in reverse order, from Z to A, use the orderby…descending clause.

For more information, see orderby clause (C# Reference).

Grouping

The group clause enables you to group your results based on a key that you specify. For example you could specify that the results should be grouped by the City so that all customers from London or Paris are in individual groups. In this case, cust.City is the key.

// queryCustomersByCity is an IEnumerable<IGrouping<string, Customer>> 
  var queryCustomersByCity =
      from cust in customers
      group cust by cust.City;

  // customerGroup is an IGrouping<string, Customer> 
  foreach (var customerGroup in queryCustomersByCity)
  {
      Console.WriteLine(customerGroup.Key);
      foreach (Customer customer in customerGroup)
      {
          Console.WriteLine("    {0}", customer.Name);
      }
  }

When you end a query with a group clause, your results take the form of a list of lists. Each element in the list is an object that has a Key member and a list of elements that are grouped under that key. When you iterate over a query that produces a sequence of groups, you must use a nested foreach loop. The outer loop iterates over each group, and the inner loop iterates over each group's members.

If you must refer to the results of a group operation, you can use the into keyword to create an identifier that can be queried further. The following query returns only those groups that contain more than two customers:

// custQuery is an IEnumerable<IGrouping<string, Customer>> 
var custQuery =
    from cust in customers
    group cust by cust.City into custGroup
    where custGroup.Count() > 2
    orderby custGroup.Key
    select custGroup;

For more information, see group clause (C# Reference).

Joining

Join operations create associations between sequences that are not explicitly modeled in the data sources. For example you can perform a join to find all the customers and distributors who have the same location. In LINQ the join clause always works against object collections instead of database tables directly.

var innerJoinQuery =
    from cust in customers
    join dist in distributors on cust.City equals dist.City
    select new { CustomerName = cust.Name, DistributorName = dist.Name };

In LINQ you do not have to use join as often as you do in SQL because foreign keys in LINQ are represented in the object model as properties that hold a collection of items. For example, a Customer object contains a collection of Order objects. Rather than performing a join, you access the orders by using dot notation:

from order in Customer.Orders...

For more information, see join clause (C# Reference).

Selecting (Projections)

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. When the select clause produces something other than a copy of the source element, the operation is called a projection. The use of projections to transform data is a powerful capability of LINQ query expressions. For more information, see Data Transformations with LINQ (C#) and select clause (C# Reference).

See Also

Tasks

Walkthrough: Writing Queries in C# (LINQ)

Reference

Anonymous Types (C# Programming Guide)

Concepts

LINQ Query Expressions (C# Programming Guide)

Basic Query Operations (Visual Basic)

Other Resources

Getting Started with LINQ in C#

Query Keywords (C# Reference)