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.

How to assign an alias to the result of a calculation

In the last figure, you saw one way to assign an alias to the result of a calculation. If you look back at the example in that figure, however, you'll see that the same calculation is performed in the where, orderby, and select clauses.To avoid that, you can use the let clause shown in figure 11-8.

As you can see, you can use the let clause to assign an alias to an expression. In the query expression in this figure, the let clause calculates the balance due for each invoice and assigns the alias BalanceDue to the result of that calculation. Then, the where, orderby, and select clauses that follow all refer to this alias.

If you look at the code that executes this query, you'll see that it's identical to the code in figure 11-7. That's possible because both queries return an anonymous type with VendorID, Number, and BalanceDue properties. However, the query expression in this figure is much simpler because the balance due is calculated only once.

The syntax of the let clause
let alias = expression

A LINQ query that assigns the result of a calculation to a variable

A query expression that calculates the balance due
var invoices = from invoice in invoiceList
               let BalanceDue = invoice.InvoiceTotal
               - invoice.PaymentTotal
               - invoice.CreditTotal
               where BalanceDue > 0
               && invoice.DueDate < DateTime.Today.AddDays(15)
               orderby invoice.VendorID,
               BalanceDue descending
               select new
               {
                   invoice.VendorID,
                   Number = invoice.InvoiceNumber,
                   BalanceDue
               };

Code that executes the query
string invoiceDisplay = "Vendor ID\tInvoice No.\tBalance Due\n";
foreach (var invoice in invoices)
{
    invoiceDisplay += invoice.VendorID + "\t\t" + invoice.Number + "\t";
    if (invoice.Number.Length < 8)
        invoiceDisplay += "\t";
    invoiceDisplay += invoice.BalanceDue.ToString("c") + "\n";
}
MessageBox.Show(invoiceDisplay, "Sorted Vendor Invoices Due");

The resulting dialog box

Description

  • The let clause lets you assign an alias to a calculation that you perform within a query. Then, you can use that alias in other clauses of the query that follow the let clause.
  • The let clause can simplify a query expression because it eliminates the need to include a calculation two or more times in the same query.

Figure 11-8 How to assign an alias to the result of a calculation

How to join data from two or more data sources

Figure 11-9 shows how you can include data from two or more data sources in a query. To do that, you use the join clause shown at the top of this figure. To start, this clause declares a range variable and names a data source just like the from clause does. Then, it indicates how the two data sources are related.

To illustrate, the first example in this figure joins data from the list of Invoice objects you've seen in the previous figures with a list of Vendor objects. To do that, it names the invoice list on the from clause, and it names the vendor list on the join clause. Then, the on condition indicates that only vendors in the vendor list with vendor IDs that match vendor IDs in the invoice list should be included in the results.

Because both the invoice and vendor lists are included as data sources in this query expression, the rest of the query can refer to properties of both Invoice and Vendor objects. For example, the where clause in this query expression compares the DueDate property of the Invoice objects to 15 days from the current date. Similarly, the orderby clause sorts the results by the Name property of the Vendor objects. And the select clause selects the Name property from the Vendor objects and the InvoiceNumber property from the Invoice objects. (All three clauses also include the balance due, which is defined by a let clause.)

The remaining code in this example executes the query and displays a list that includes the vendor names, invoice numbers, and balances due. This is similar to the lists you saw in figures 11-6 and 11-8. Because the list in this figure includes the vendor names instead of the vendor IDs, however, it provides more useful information.

Although this figure only shows how to join data from two data sources, you can extend this syntax to join data from additional data sources. For example, suppose you have three data sources named vendorList, invoiceList, and lineItemList. Then, you could join the data in these lists using code like this:

from vendor in vendorList
join invoice in invoiceList
on vendor.vendorID equals invoice.vendorID
join lineItem in lineItemList
on invoice.invoiceID equals lineItem.invoiceID...

Once the three lists are joined, you can refer to properties from any of these lists in the query expression.

The basic syntax of the join clause
join elementName in collectionName on keyName1 equals keyName2

A LINQ query that joins data from two data sources

A query expression that joins data from generic lists of invoices and vendors
var invoices = from invoice in invoiceList
              join vendor in vendorList
              on invoice.VendorID equals vendor.VendorID
              let BalanceDue = invoice.InvoiceTotal
              - invoice.PaymentTotal
              - invoice.CreditTotal
              where BalanceDue > 0
              && invoice.DueDate < DateTime.Today.AddDays(15)
              orderby vendor.Name, BalanceDue descending
              select new
              {
                  vendor.Name,
                  Number = invoice.InvoiceNumber,
                  BalanceDue
              };

Code that executes the query
string invoiceDisplay = "Vendor Name\t\t\tInvoice No.\tBalance Due\n";
foreach (var invoice in invoices)
{
    invoiceDisplay += invoice.Name + "\t\t";
    if (invoice.Name.Length < 20)
        invoiceDisplay += "\t";
    if (invoice.Name.Length < 10)
        invoiceDisplay += "\t";
    invoiceDisplay += invoice.Number + "\t";
    if (invoice.Number.Length < 8)
        invoiceDisplay += "\t";
    invoiceDisplay += invoice.BalanceDue.ToString("c") + "\n";
}
MessageBox.Show(invoiceDisplay, "Joined Vendor and Invoice Data");

The resulting dialog box

Description

  • The join clause lets you combine data from two or more data sources based on matching key values. The query results will include only those elements that meet the condition specified by the equals operator.
  • You can extend the syntax shown above to join data from additional data sources.

Figure 11-9 How to join data from two or more data sources

Total Pages : 10 45678

comments