FREE BOOK

Chapter 11: An introduction to LINQ

Posted by Murach Free Book | LINQ August 13, 2009
In this chapter, you’ll learn the basic concepts and skills for using a new feature of C# 2008 called LINQ. To illustrate these concepts and skills, I’ll use an implementation of LINQ called LINQ to Objects. You use LINQ to Objects to work with in-memory data structures such as generic lists and arrays.

The three stages of a query operation

Figure 11-3 presents the three stages of a query operation and illustrates these stages using a generic list. The first stage is to get the data source. How you do that depends on the type of data source you're working with. For the generic list shown here, getting the data source means declaring a variable to hold the list and then calling a method that returns a List<Invoice> object.

The second stage is to define the query expression. This expression identifies the data source and the data to be retrieved from that data source. The query expression in this figure, for example, retrieves all the invoices with an invoice total greater than 20,000. It also sorts those invoices by invoice total in descending sequence. (Don't worry if you don't understand the syntax of this query expression. You'll learn how to code query expressions in the topics that follow.)

Notice here that the query expression is stored in a query variable. That's necessary because this query isn't executed when it's defined. Also notice that the query variable is declared with the var keyword. This keyword indicates that the variable will be given a type implicitly based on the type of elements returned by the query. As you learned in the previous figure, this is one of the new features of C#. In this case, because the query returns Invoice objects, the query variable is given the type IEnumerable<Invoice>.

For this to work, the data source must be an enumerable type, which means that it implements the IEnumerable<T> interface. The data source can also implement the IQueryable<T> interface since this interface implements IEnumerable<T>. In case you're not familiar with interfaces, they consist of a set of declarations for one or more properties, methods, and events, but they don't provide implementation for those properties, methods, and events. For the example in this figure, however, all you need to know is that the List<> class implements the IEnumerable<T> interface.

The third stage of a query operation is to execute the query. To do that, you typically use a foreach statement like the one shown in this figure. Here, each element that's returned by the query expression is added to a string variable. Then, after all the elements have been processed, the string is displayed in a message box. As you can see, this message box lists the invoice numbers and invoice totals for all invoices with totals greater than 20,000.

When a query is defined and executed separately as shown here, the process is referred to as deferred execution. In contrast, queries that are executed when they're defined use immediate execution. Immediate execution typically occurs when a method that requires access to the individual elements returned by the query is executed on the query expression. For example, to get a count of the number of elements returned by a query, you can execute the Count method on the query expression. Then, the query will be executed immediately so the count can be calculated. You'll learn about some of the methods for returning these types of values later in this chapter.

The three stages of a query operation

  1. Get the data source. If the data source is a generic list, for example, you must declare and populate the list object.
  2. Define the query expression.
  3. Execute the query to return the results.

A LINQ query that retrieves data from a generic list of invoices

A statement that declares and populates the list

List<Invoice> invoiceList = InvoiceDB.GetInvoices();

A statement that defines the query expression

var invoices = from invoice in invoiceList

               where invoice.InvoiceTotal > 20000

               orderby invoice.InvoiceTotal descending

               select invoice;

Code that executes the query
string invoiceDisplay = "Invoice No.\tInvoice Total\n";
foreach (var invoice in invoices)
{
    invoiceDisplay += invoice.InvoiceNumber + "\t\t" +
    invoice.InvoiceTotal.ToString("c") + "\n";
}
MessageBox.Show(invoiceDisplay, "Invoices Over $20,000");

The resulting dialog box

Description

  • The process described above is called deferred execution because the query isn't executed when it's defined. Instead, it's executed when the application tries to access the individual elements returned by the query, such as when the query is used in a foreach statement.
  • If a query isn't executed when it's defined, it's stored in a query variable. In that case, the query variable can be implicitly typed as IEnumerable<T> where T is the type of each element. In the example above, the invoices variable is assigned the type IEnumerable<Invoice> since the invoice list contains Invoice objects.
  • If a query requires access to the individual elements identified by the query expression, such as when an aggregate value is requested, immediate execution occurs. In that case, the query expression isn't saved in a query variable.

Figure 11-3 The three stages of a query operation

Total Pages : 10 12345

comments