How to code query expressions
Now that you have a basic understanding of what a LINQ query is, you need to learn the syntax for coding query expressions. That's what you'll learnin the topics that follow.
How to identify the data source for a query
To identify the source of data for a query, you use the from clause shown in figure 11-4. As you can see, this clause declares a range variable that will be used to represent each element of the data source, and it names the data source, which must be an enumerable type. Note that because the result of a query is an enumerable type, the data source can be a previously declared query variable. The from clause can also declare a type for the range variable, although the type is usually omitted. If it is omitted, it's determined by the type of elements in the data source.
The example in this figure shows how to use the from clause with a generic list of invoices. The first statement in this example creates a list that's based on the Invoice class and loads invoices into it using the GetInvoices method of the InvoiceDB class. Note that the Invoice class used in this example and other examples in this chapter is identical to the class presented in figure 6-7 of chapter 6, except that it doesn't include a BalanceDue method. Also note that it's not important for you to know how the GetInvoices method of the InvoiceDB class works. All you need to know is that this method returns a List<Invoice> object. This object is then assigned to a variable named invoiceList.
The second statement defines the query expression, which consists of just the from clause and a select clause. The from clause uses the name invoice for the range variable, and it identifies invoiceList as the data source. This expression is then stored in a query variable named invoices. Finally, the code that follows uses a foreach statement to loop through the invoices and calculate a sum of the InvoiceTotal field for each invoice.
At this point, you should realize that a query expression must always start with a from clause that identifies the data source. That way, C# knows what the source of data for the query is, and it can help you construct the rest of the query based on that data source. In addition, a query expression must end with either a select clause or a group clause. In the example in this figure, the select clause simply indicates that Invoice objects should be returned by the query. Later in this chapter, however, you'll see that you can use the select clause to return just the fields you want from each element of a data source.
You may have noticed in this example that the variable that's used in the query expression and the variable that's used in the foreach loop have the same name. That makes sense because they both refer to an element in the data source. However, you should know that you don't have to use the same names for these variables. In fact, when you code more sophisticated query expressions, you'll want to use different variable names to indicate the differences between the elements they refer to. That'll make more sense when you see the group clause later in this chapter.
The syntax of the from clause
from [type] elementName in collectionName
A LINQ query that includes just a From clause
A statement that declares and populates a generic list of invoicesList<Invoice> invoiceList = InvoiceDB.GetInvoices();
A statement that defines the query expression
var invoices = from invoice in invoiceList
select invoice;
Code that executes the query
decimal sum = 0;
foreach (var invoice in invoiceList)
{
sum += invoice.InvoiceTotal;
}
MessageBox.Show(sum.ToString("c"), "Sum of Invoices");
The resulting dialog box
Description
Figure 11-4 How to identify the data source for a query
How to filter the results of a query
To filter the results of a query, you use the where clause shown in figure 11-5. On this clause, you specify a condition that an element must meet to be returned by the query. The condition is coded as a Boolean expression. The example in this figure illustrates how this works.
The where clause in this example specifies that for an element to be returned from the generic list of invoices, the invoice's balance due, which is calculated by subtracting its PaymentTotal and CreditTotal columns from its InvoiceTotal column, must be greater than zero. In addition, the due date must be less than 15 days from the current date. Notice here that the range variable that's declared by the from clause is used in the where clause to refer to each Invoice object. Then, the foreach statement that executes the query refers to the VendorID, InvoiceNumber, InvoiceTotal, PaymentTotal, and CreditTotal properties of each Invoice object that's returned by the query to create a string that's displayed in a message box.
The syntax of the where clausewhere condition
A LINQ query that filters the generic list of invoices
A query expression that returns invoices with a balance due within the next 15 days
where invoice.InvoiceTotal
- invoice.PaymentTotal
- invoice.CreditTotal > 0
&& invoice.DueDate < DateTime.Today.AddDays(15)
string invoiceDisplay = "Vendor ID\tInvoice No.\tBalance Due\n";
foreach (var invoice in invoices)
invoiceDisplay += invoice.VendorID + "\t\t" +
invoice.InvoiceNumber + "\t";
if (invoice.InvoiceNumber.Length < 8)
invoiceDisplay += "\t";
invoiceDisplay += (invoice.InvoiceTotal - invoice.PaymentTotal
- invoice.CreditTotal).ToString("c") + "\n";
MessageBox.Show(invoiceDisplay, "Vendor Invoices Due");
Figure 11-5 How to filter the results of a query