Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# 2008 Step by Step.pdf
Скачиваний:
27
Добавлен:
25.03.2016
Размер:
14 Мб
Скачать
☆

372 Part III Creating Components

The designers of LINQ took an unabashed look at the way in which relational database management systems, such as Microsoft SQL Server, separate the language used to query a database from the internal format of the data in the database. Developers accessing a SQL Server database issue Structured Query Language (SQL) statements to the database management system. SQL provides a high-level description of the data that the developer wants to retrieve but does not indicate exactly how the database management system should retrieve this data. These details are controlled by the database management system itself. Consequently, an application that invokes SQL statements does not care how the database management system physically stores or retrieves data. The format used by the database management system can change (for example, if a new version is released) without the application developer needing to modify the SQL statements used by the application.

LINQ provides syntax and semantics very reminiscent of SQL, and with many of the same advantages. You can change the underlying structure of the data being queried without needing to change the code that actually performs the queries. You should be aware that although LINQ looks similar to SQL, it is far more flexible and can handle a wider variety of logical data structures. For example, LINQ can handle data organized hierarchically, such as that found in an XML document. However, this chapter concentrates on using LINQ in a relational manner.

Using LINQ in a C# Application

Perhaps the easiest way to explain how to use the C# features that support LINQ is to work through some simple examples based on the following sets of customer and address information:

Customer Information

CustomerID

FirstName

LastName

CompanyName

1

Orlando

Gee

A Bike Store

 

 

 

 

2

Keith

Harris

Bike World

 

 

 

 

3

Donna

Carreras

A Bike Store

 

 

 

 

4

Janet

Gates

Fitness Hotel

 

 

 

 

5

Lucy

Harrington

Grand Industries

 

 

 

 

6

David

Liu

Bike World

 

 

 

 

7

Donald

Blanton

Grand Industries

 

 

 

 

8

Jackie

Blackwell

Fitness Hotel

 

 

 

 

9

Elsa

Leavitt

Grand Industries

 

 

 

 

10

Eric

Lang

Distant Inn

 

 

 

 

Chapter 20 Querying In-Memory Data by Using Query Expressions

373

Address Information

CompanyName

City

Country

A Bike Store

New York

United States

 

 

 

Bike World

Chicago

United States

 

 

 

Fitness Hotel

Ottawa

Canada

 

 

 

Grand Industries

London

United Kingdom

 

 

 

Distant Inn

Tetbury

United Kingdom

 

 

 

LINQ requires the data to be stored in a data structure that implements the IEnumerable in-

terface, as described in Chapter 19, “Enumerating Collections.” It does not matter what structure you use (an array, a HashTable, a Queue, or any of the other collection types, or even one

that you define yourself) as long as it is enumerable. However, to keep things straightfor-

ward, the examples in this chapter assume that the customer and address information is held in the customers and addresses arrays shown in the following code example.

Note In a real-world application, you would populate these arrays by reading the data from a file or a database. You will learn more about the features provided by the .NET Framework for retrieving information from a database in Part V of this book, “Managing Data”.

var customers = new[] {

new { CustomerID = 1, FirstName = “Orlando”, LastName = “Gee”, CompanyName = “A Bike Store” },

new { CustomerID = 2, FirstName = “Keith”, LastName = “Harris”, CompanyName = “Bike World” },

new { CustomerID = 3, FirstName = “Donna”, LastName = “Carreras”, CompanyName = “A Bike Store” },

new { CustomerID = 4, FirstName = “Janet”, LastName = “Gates”, CompanyName = “Fitness Hotel” },

new { CustomerID = 5, FirstName = “Lucy”, LastName = “Harrington”, CompanyName = “Grand Industries” },

new { CustomerID = 6, FirstName = “David”, LastName = “Liu”, CompanyName = “Bike World” },

new { CustomerID = 7, FirstName = “Donald”, LastName = “Blanton”, CompanyName = “Grand Industries” },

new { CustomerID = 8, FirstName = “Jackie”, LastName = “Blackwell”, CompanyName = “Fitness Hotel” },

new { CustomerID = 9, FirstName = “Elsa”, LastName = “Leavitt”, CompanyName = “Grand Industries” },

new { CustomerID = 10, FirstName = “Eric”, LastName = “Lang”, CompanyName = “Distant Inn” }

};

374Part III Creating Components

var addresses = new[] {

new { CompanyName = “A Bike Store”, City = “New York”, Country = “United States”}, new { CompanyName = “Bike World”, City = “Chicago”, Country = “United States”}, new { CompanyName = “Fitness Hotel”, City = “Ottawa”, Country = “Canada”},

new { CompanyName = “Grand Industries”, City = “London”, Country = “United Kingdom”},

new { CompanyName = “Distant Inn”, City = “Tetbury”, Country = “United Kingdom”}

};

Note The following sections, “Selecting Data,” “Filtering Data,” “Ordering, Grouping, and Aggregating Data,” and “Joining Data,” show you the basic capabilities and syntax for querying data by using LINQ methods. The syntax can become a little complex at times, and you will see when you reach the section “Using Query Operators” that it is not actually necessary to remember how the syntax all works. However, it is useful for you to at least take a look at the following sections so that you can fully appreciate how the query operators provided with C# perform their tasks.

Selecting Data

Suppose you want to display a list comprising the first name of each customer in the customers array. You can achieve this task with the following code:

IEnumerable<string> customerFirstNames = customers.Select(cust => cust.FirstName);

foreach (string name in customerFirstNames)

{

Console.WriteLine(name);

}

Although this block of code is quite short, it does a lot, and it requires a degree of explanation, starting with the use of the Select method of the customers array.

The Select method enables you to retrieve specific data from the array—in this case, just the value in the FirstName field of each item in the array. How does it work? The parameter to the Select method is actually another method that takes a row from the customers array and

returns the selected data from that row. You could define your own custom method to perform this task, but the simplest mechanism is to use a lambda expression to define an anonymous method, as shown in the preceding example. There are three important things that you need to understand at this point:

The type cust is the type of the parameter passed in to the method. You can think of cust as an alias for the type of each row in the customers array. The compiler deduces this from the fact that you are calling the Select method on the customers array. You can use any legal C# identifier in place of cust.

Chapter 20 Querying In-Memory Data by Using Query Expressions

375

The Select method does not actually retrieve the data at this time; it simply returns an enumerable object that will fetch the data identified by the Select method when

you iterate over it later. We will return to this aspect of LINQ in the section “LINQ and Deferred Evaluation” later in this chapter.

The Select method is not actually a method of the Array type. It is an extension method of the Enumerable class. The Enumerable class is located in the System.Linq namespace

and provides a substantial set of static methods for querying objects that implement the generic IEnumerable<T> interface.

The preceding example uses the Select method of the customers array to generate an

IEnumerable<string> object named customerFirstNames. (It is of type IEnumerable<string> because the Select method returns an enumerable collection of customer first names, which are strings.) The foreach statement iterates through this collection of strings, printing out the first name of each customer in the following sequence:

Orlando

Keith

Donna

Janet

Lucy

David

Donald

Jackie

Elsa

Eric

You can now display the first name of each customer. How do you fetch the first and last

name of each customer? This task is slightly trickier. If you examine the definition of the Enumerable.Select method in the System.Linq namespace in the documentation supplied with

Microsoft Visual Studio 2008, you will see that it looks like this:

public static IEnumerable<TResult> Select<TSource, TResult> ( IEnumerable<TSource> source,

Func<TSource, TResult> selector

)

What this actually says is that Select is a generic method that takes two type parameters named TSource and TResult, as well as two ordinary parameters named source and selector. TSource is the type of the collection that you are generating an enumerable set of results for (customer objects in our example), and TResult is the type of the data in the enumerable set of results (string objects in our example). Remember that Select is an extension method, so

the source parameter is actually a reference to the type being extended (a generic collection of customer objects that implements the IEnumerable interface in our example). The selector

parameter specifies a generic method that identifies the fields to be retrieved. (Func is the

name of a generic delegate type in the .NET Framework that you can use for encapsulating a generic method.) The method referred to by the selector parameter takes a TSource (in

376 Part III Creating Components

this case, customer) parameter and yields a collection of TResult (in this case, string) objects. The value returned by the Select method is an enumerable collection of TResult (again string)

objects.

Note If you need to review how extension methods work and the role of the first parameter to an extension method, go back and revisit Chapter 12, “Working with Inheritance.”

The important point to understand from the preceding paragraph is that the Select method returns an enumerable collection based on a single type. If you want the enumerator to return multiple items of data, such as the first and last name of each customer, you have at least two options:

You can concatenate the first and last names together into a single string in the Select method, like this:

IEnumerable<string> customerFullName =

customers.Select(cust => cust.FirstName + " " + cust.LastName);

You can define a new type that wraps the first and last names and use the Select method to construct instances of this type, like this:

class Names

{

public string FirstName{ get; set; } public string LastName{ get; set; }

}

...

IEnumerable<Names> customerName =

customers.Select(cust => new Names { FirstName = cust.FirstName, LastName = cust.LastName } );

The second option is arguably preferable, but if this is the only use that your application makes of the Names type, you might prefer to use an anonymous type instead of defining a

new type specifically for a single operation, like this:

var customerName =

customers.Select(cust => new { FirstName = cust.FirstName, LastName = cust.LastName } );

Notice the use of the var keyword here to define the type of the enumerable collection. The type of objects in the collection is anonymous, so you cannot specify a specific type for the objects in the collection.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]