Tải bản đầy đủ (.pdf) (10 trang)

Professional ASP.NET 3.5 in C# and Visual Basic Part 51 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (92.88 KB, 10 trang )

Evjen c09.tex V2 - 01/28/2008 2:09pm Page 456
Chapter 9: Querying with LINQ
Listing 9-1: A basic Movie class
VB
Imports Microsoft.VisualBasic
Public Class Movie
Private _title As String
Private _director As String
Private _genre As Integer
Private _runtime As Integer
Private _releasedate As DateTime
Public Property Title() As String
Get
Return _title
End Get
Set(ByVal value As String)
_title = value
End Set
End Property
Public Property Director() As String
Get
Return _director
End Get
Set(ByVal value As String)
_director = value
End Set
End Property
Public Property Genre() As Integer
Get
Return _genre
End Get


Set(ByVal value As Integer)
_genre = value
End Set
End Property
Public Property Runtime() As Integer
Get
Return _runtime
End Get
Set(ByVal value As Integer)
_runtime = value
End Set
End Property
Public Property ReleaseDate() As DateTime
Get
Return _releasedate
End Get
Set(ByVal value As DateTime)
456
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 457
Chapter 9: Querying with LINQ
_releasedate = value
End Set
End Property
End Class
C#
using System;
public class Movie
{
public string Title { get; set; }
public string Director { get; set; }

public int Genre { get; set; }
public int RunTime { get; set; }
public DateTime ReleaseDate { get; set; }
}
This is the basic class that is used throughout this section and the following LINQ to Object section.
Now that you have a basic class to work with, let’s look at how you would normally use the class. Listing
9-2 demonstrates how to create a simple generic List of the Movie objects in an ASP.NET page, and then
binding that list to a GridView control. The GridView displays the values of all public properties exposed
by the Movie class.
Listing 9-2: Generating a list of Movie objects and binding to a GridView
VB
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim movies = GetMovies()
Me.GridView1.DataSource = movies
Me.GridView1.DataBind()
End Sub
Public Function GetMovies() As List(Of Movie)
Dim movies As Movie() = { _
New Movie With {.Title = "Shrek", .Director = "Andrew Adamson", _
.Genre = 0, .ReleaseDate = DateTime.Parse("5/16/2001"),
.Runtime = 89}, _
New Movie With {.Title = "Fletch", .Director = "Michael Ritchie", _
.Genre = 0, .ReleaseDate = DateTime.Parse("5/31/1985"),
.Runtime = 96}, _
New Movie With {.Title = "Casablanca", .Director = "Michael Curtiz", _
.Genre = 1, .ReleaseDate = DateTime.Parse("1/1/1942"),
.Runtime = 102}, _

New Movie With {.Title = "Batman", .Director = "Tim Burton", _
.Genre = 1, .ReleaseDate = DateTime.Parse("6/23/1989"),
.Runtime = 126}, _
Continued
457
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 458
Chapter 9: Querying with LINQ
New Movie With {.Title = "Dances with Wolves",
.Director = "Kevin Costner", _
.Genre = 1, .ReleaseDate = DateTime.Parse("11/21/1990"),
.Runtime = 180}, _
New Movie With {.Title = "Dirty Dancing", .Director = "Emile Ardolino", _
.Genre = 1, .ReleaseDate = DateTime.Parse("8/21/1987"),
.Runtime = 100}, _
New Movie With {.Title = "The Parent Trap", .Director = "Nancy Meyers", _
.Genre = 0, .ReleaseDate = DateTime.Parse("7/29/1998"),
.Runtime = 127}, _
New Movie With {.Title = "Ransom", .Director = "Ron Howard", _
.Genre = 1, .ReleaseDate = DateTime.Parse("11/8/1996"),
.Runtime = 121}, _
New Movie With {.Title = "Ocean’s Eleven", .Director = "Steven Soderbergh", _
.Genre = 1, .ReleaseDate = DateTime.Parse("12/7/2001"),
.Runtime = 116}, _
New Movie With {.Title = "Steel Magnolias", .Director = "Herbert Ross", _
.Genre = 1, .ReleaseDate = DateTime.Parse("11/15/1989"),
.Runtime = 117}, _
New Movie With {.Title = "Mystic Pizza", .Director = "Donald Petrie", _
.Genre = 1, .ReleaseDate = DateTime.Parse("10/21/1988"),
.Runtime = 104}, _
New Movie With {.Title = "Pretty Woman", .Director = "Garry Marshall", _

.Genre = 1, .ReleaseDate = DateTime.Parse("3/23/1990"),
.Runtime = 119}, _
New Movie With {.Title = "Interview with the Vampire",
.Director = "Neil Jordan", _
.Genre = 1, .ReleaseDate = DateTime.Parse("11/11/1994"),
.Runtime = 123}, _
New Movie With {.Title = "Top Gun", .Director = "Tony Scott", _
.Genre = 2, .ReleaseDate = DateTime.Parse("5/16/1986"),
.Runtime = 110}, _
New Movie With {.Title = "Mission Impossible",
.Director = "Brian De Palma", _
.Genre = 2, .ReleaseDate = DateTime.Parse("5/22/1996"),
.Runtime = 110}, _
New Movie With {.Title = "The Godfather",
.Director = "Francis Ford Coppola", _
.Genre = 1, .ReleaseDate = DateTime.Parse("3/24/1972"),
.Runtime = 175}, _
New Movie With {.Title = "Carlito’s Way", .Director = "Brian De Palma", _
.Genre = 1, .ReleaseDate = DateTime.Parse("11/10/1993"),
.Runtime = 144}, _
New Movie With {.Title = "Robin Hood: Prince of Thieves", _
.Director = "Kevin Reynolds", .Genre = 1, _
.ReleaseDate = DateTime.Parse("6/14/1991"), .Runtime = 143}, _
New Movie With {.Title = "The Haunted", .Director = "Robert Mandel", _
.Genre = 1, .ReleaseDate = DateTime.Parse("5/6/1991"),
.Runtime = 100}, _
New Movie With {.Title = "Old School", .Director = "Todd Phillips", _
.Genre = 0, .ReleaseDate = DateTime.Parse("2/21/2003"),
.Runtime = 91}, _
New Movie With {.Title = "Anchorman: The Legend of Ron Burgundy", _

Continued
458
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 459
Chapter 9: Querying with LINQ
.Director = "Adam McKay", .Genre = 0, _
.ReleaseDate = DateTime.Parse("7/9/2004"),
.Runtime = 94}, _
New Movie With {.Title = "Bruce Almighty", .Director = "Tom Shadyac", _
.Genre = 0, .ReleaseDate = DateTime.Parse("5/23/2003"),
.Runtime = 101}, _
New Movie With {.Title = "Ace Ventura: Pet Detective", _
.Director = "Tom Shadyac", .Genre = 0, _
.ReleaseDate = DateTime.Parse("2/4/1994"),
.Runtime = 86}, _
New Movie With {.Title = "Goonies", .Director = "Richard Donner", _
.Genre = 0, .ReleaseDate = DateTime.Parse("6/7/1985"),
.Runtime = 114}, _
New Movie With {.Title = "Sixteen Candles", .Director = "John Hughes", _
.Genre = 1, .ReleaseDate = DateTime.Parse("5/4/1984"),
.Runtime = 93}, _
New Movie With {.Title = "The Breakfast Club", .Director = "John Hughes", _
.Genre = 1, .ReleaseDate = DateTime.Parse("2/15/1985"),
.Runtime = 97}, _
New Movie With {.Title = "Pretty in Pink", .Director = "Howard Deutch", _
.Genre = 1, .ReleaseDate = DateTime.Parse("2/28/1986"),
.Runtime = 96}, _
New Movie With {.Title = "Weird Science", .Director = "John Hughes", _
.Genre = 0, .ReleaseDate = DateTime.Parse("8/2/1985"),
.Runtime = 94}, _
New Movie With {.Title = "Breakfast at Tiffany’s", .Director =

"Blake Edwards", _
.Genre = 1, .ReleaseDate = DateTime.Parse("10/5/1961"),
.Runtime = 115}, _
New Movie With {.Title = "The Graduate", .Director = "Mike Nichols", _
.Genre = 1, .ReleaseDate = DateTime.Parse("4/2/1968"),
.Runtime = 105}, _
New Movie With {.Title = "Dazed and Confused", .Director = "Richard
Linklater", _
.Genre = 0, .ReleaseDate = DateTime.Parse("9/24/1993"),
.Runtime = 103}, _
New Movie With {.Title = "Arthur", .Director = "Steve Gordon", _
.Genre = 1, .ReleaseDate = DateTime.Parse("9/25/1981"),
.Runtime = 97}, _
New Movie With {.Title = "Monty Python and the Holy Grail", _
.Director = "Terry Gilliam", .Genre = 0, _
.ReleaseDate = DateTime.Parse("5/10/1975"),
.Runtime = 91}, _
New Movie With {.Title = "Dirty Harry", .Director = "Don Siegel", _
.Genre = 2, .ReleaseDate = DateTime.Parse("12/23/1971"),
.Runtime = 102} _
}
Return New List(Of Movie)(movies)
End Function
</script>
<html xmlns=" /><head runat="server">
Continued
459
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 460
Chapter 9: Querying with LINQ
<title>My Favorite Movies</title>

</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
</div>
</form>
</body>
</html>
C#
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
var movies = GetMovies();
this.GridView1.DataSource = movies;
this.GridView1.DataBind();
}
public List<Movie> GetMovies()
{
return new List<Movie> {
new Movie { Title="Shrek", Director="Andrew Adamson", Genre=0,
ReleaseDate=DateTime.Parse("5/16/2001"), RunTime=89 } ,
new Movie { Title="Fletch", Director="Michael Ritchie", Genre=0,
ReleaseDate=DateTime.Parse("5/31/1985"), RunTime=96 } ,
new Movie { Title="Casablanca", Director="Michael Curtiz", Genre=1,
ReleaseDate=DateTime.Parse("1/1/1942"), RunTime=102 } ,
new Movie { Title="Batman", Director="Tim Burton", Genre=1,
ReleaseDate=DateTime.Parse("6/23/1989"), RunTime=126 } ,
new Movie { Title="Dances with Wolves", Director="Kevin Costner",Genre=1,

ReleaseDate=DateTime.Parse("11/21/1990"), RunTime=180 } ,
new Movie { Title="Dirty Dancing", Director="Emile Ardolino", Genre=1,
ReleaseDate=DateTime.Parse("8/21/1987"), RunTime=100 } ,
new Movie { Title="The Parent Trap", Director="Nancy Meyers", Genre=0,
ReleaseDate=DateTime.Parse("7/29/1998"), RunTime=127 } ,
new Movie { Title="Ransom", Director="Ron Howard", Genre=1,
ReleaseDate=DateTime.Parse("11/8/1996"), RunTime=121 } ,
new Movie { Title="Ocean’s Eleven", Director="Steven
Soderbergh", Genre=1,
ReleaseDate=DateTime.Parse("12/7/2001"), RunTime=116 } ,
new Movie { Title="Steel Magnolias", Director="Herbert Ross", Genre=1,
ReleaseDate=DateTime.Parse("11/15/1989"), RunTime=117 } ,
new Movie { Title="Mystic Pizza", Director="Donald Petrie", Genre=1,
ReleaseDate=DateTime.Parse("10/21/1988"), RunTime=104 } ,
new Movie { Title="Pretty Woman", Director="Garry Marshall", Genre=1,
ReleaseDate=DateTime.Parse("3/23/1990"), RunTime=119 } ,
new Movie { Title="Interview with the Vampire",
Director="Neil Jordan", Genre=1,
ReleaseDate=DateTime.Parse("11/11/1994"), RunTime=123 } ,
Continued
460
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 461
Chapter 9: Querying with LINQ
new Movie { Title="Top Gun", Director="Tony Scott", Genre=2,
ReleaseDate=DateTime.Parse("5/16/1986"), RunTime=110 } ,
new Movie { Title="Mission Impossible", Director="Brian De Palma", Genre=2,
ReleaseDate=DateTime.Parse("5/22/1996"), RunTime=110 } ,
new Movie { Title="The Godfather", Director="Francis Ford Coppola",
Genre=1, ReleaseDate=DateTime.Parse("3/24/1972"), RunTime=175 } ,
new Movie { Title="Carlito’s Way", Director="Brian De Palma",

Genre=1, ReleaseDate=DateTime.Parse("11/10/1993"), RunTime=144 } ,
new Movie { Title="Robin Hood: Prince of Thieves",
Director="Kevin Reynolds",
Genre=1, ReleaseDate=DateTime.Parse("6/14/1991"), RunTime=143 } ,
new Movie { Title="The Haunted", Director="Robert Mandel",
Genre=1, ReleaseDate=DateTime.Parse("5/6/1991"), RunTime=100 } ,
new Movie { Title="Old School", Director="Todd Phillips",
Genre=0, ReleaseDate=DateTime.Parse("2/21/2003"), RunTime=91 } ,
new Movie { Title="Anchorman: The Legend of Ron Burgundy",
Director="Adam McKay", Genre=0,
ReleaseDate=DateTime.Parse("7/9/2004"), RunTime=94 } ,
new Movie { Title="Bruce Almighty", Director="Tom Shadyac",
Genre=0, ReleaseDate=DateTime.Parse("5/23/2003"), RunTime=101 } ,
new Movie { Title="Ace Ventura: Pet Detective", Director="Tom Shadyac",
Genre=0, ReleaseDate=DateTime.Parse("2/4/1994"), RunTime=86 } ,
new Movie { Title="Goonies", Director="Richard Donner",
Genre=0, ReleaseDate=DateTime.Parse("6/7/1985"), RunTime=114 } ,
new Movie { Title="Sixteen Candles", Director="John Hughes",
Genre=1, ReleaseDate=DateTime.Parse("5/4/1984"), RunTime=93 } ,
new Movie { Title="The Breakfast Club", Director="John Hughes",
Genre=1, ReleaseDate=DateTime.Parse("2/15/1985"), RunTime=97 } ,
new Movie { Title="Pretty in Pink", Director="Howard Deutch",
Genre=1, ReleaseDate=DateTime.Parse("2/28/1986"), RunTime=96 } ,
new Movie { Title="Weird Science", Director="John Hughes",
Genre=0, ReleaseDate=DateTime.Parse("8/2/1985"), RunTime=94 } ,
new Movie { Title="Breakfast at Tiffany’s", Director="Blake Edwards",
Genre=1, ReleaseDate=DateTime.Parse("10/5/1961"), RunTime=115 } ,
new Movie { Title="The Graduate", Director="Mike Nichols",
Genre=1, ReleaseDate=DateTime.Parse("4/2/1968"), RunTime=105 } ,
new Movie { Title="Dazed and Confused", Director="Richard Linklater",

Genre=0, ReleaseDate=DateTime.Parse("9/24/1993"), RunTime=103 } ,
new Movie { Title="Arthur", Director="Steve Gordon",
Genre=1, ReleaseDate=DateTime.Parse("9/25/1981"), RunTime=97 } ,
new Movie { Title="Monty Python and the Holy Grail",
Director="Terry Gilliam",
Genre=0, ReleaseDate=DateTime.Parse("5/10/1975"), RunTime=91 } ,
new Movie { Title="Dirty Harry", Director="Don Siegel",
Genre=2, ReleaseDate=DateTime.Parse("12/23/1971"), RunTime=102 }
};
}
</script>
Running the sample generates a typical ASP.NET Web page that includes a simple grid showing all of
the Movie data on it.
Now, what happens when you want to start performing queries on the list of movies? For example, you
might want to filter this data to show only a specific genre of movie. Listing 9-3 shows a typical way you
might perform this filtering.
461
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 462
Chapter 9: Querying with LINQ
Listing 9-3: Filtering the listing Movie objects
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim movies = GetMovies()
Dim query As New List(Of Movie)()
For Each m In movies
If (m.Genre = 0) Then
query.Add(m)
End If
Next
Me.GridView1.DataSource = query

Me.GridView1.DataBind()
End Sub
C#
protected void Page_Load(object sender, EventArgs e)
{
var movies = GetMovies();
var query = new List<Movie>();
foreach (var m in movies)
{
if (m.Genre == 0) query.Add(m);
}
this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
As this sample shows, to filter the data so that the page displays Movies in a specific genre only requires
the creation of a new temporary collection and the use of a
foreach
loop to iterate through the data.
While this technique seems easy enough, it still requires that you define what you want done (find all
movies in the genre), and also that you explicitly define how it should be done (use a temporary collection
and a
foreach
loop). Additionally, what happens when you need to perform more complex queries,
involving grouping or sorting? Now the complexity of the code dramatically increases, as shown in
Listing 9-4.
Listing 9-4: Grouping and sorting the List of Movie objects
VB
Public Class Grouping
Private _genre As Integer
Private _movieCount As Integer

Public Property Genre() As Integer
Get
Return _genre
Continued
462
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 463
Chapter 9: Querying with LINQ
End Get
Set(ByVal value As Integer)
_genre = value
End Set
End Property
Public Property MovieCount() As Integer
Get
Return _movieCount
End Get
Set(ByVal value As Integer)
_movieCount = value
End Set
End Property
End Class
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim movies = GetMovies()
Dim groups As New Dictionary(Of String, Grouping)
For Each m In movies
If (Not groups.ContainsKey(m.Genre)) Then
groups(m.Genre) = _
New Grouping With {.Genre = m.Genre, .MovieCount = 0}
End If
groups(m.Genre).MovieCount = groups(m.Genre).MovieCount + 1

Next
Dim results As New List(Of Grouping)(groups.Values)
results.Sort(AddressOf MovieSort)
Me.GridView1.DataSource = results
Me.GridView1.DataBind()
End Sub
Private Function MovieSort(ByVal x As Grouping, ByVal y As Grouping) As Integer
Return IIf(x.MovieCount > y.MovieCount, -1, IIf(x.MovieCount
< y.MovieCount, 1, 0))
End Function
C#
public class Grouping
{
public int Genre { get; set; }
public int MovieCount { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
var movies = GetMovies();
Continued
463
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 464
Chapter 9: Querying with LINQ
Dictionary<int, Grouping> groups = new Dictionary<int, Grouping>();
foreach (Movie m in movies)
{
if (!groups.ContainsKey(m.Genre))
{
groups[m.Genre] = new Grouping { Genre = m.Genre, MovieCount = 0 };
}

groups[m.Genre].MovieCount++;
}
List<Grouping> results = new List<Grouping>(groups.Values);
results.Sort(delegate(Grouping x, Grouping y)
{
return
x.MovieCount > y.MovieCount ? -1 :
x.MovieCount < y.MovieCount ? 1 :
0;
});
this.GridView1.DataSource = results;
this.GridView1.DataBind();
}
To group the Movie data into genres and count how many movies are in each genre requires the addition
of a new class, the creation of a Dictionary, and the implementation of a delegate, all fairly complex
requirements for such a seemingly simple task, and again, not only defining very specifically what you
want done, but very explicitly how it should be done.
Additionally, because the complexity of the code increases so much, it becomes quite difficult to actually
determine what this code is doing. Consider this: What if you were asked to modify this code in an
existing application that you were unfamiliar with? How long would it take you to figure out what it
was doing?
Replacing Traditional Queries with LINQ
LINQ was created to address many of the shortcomings of querying collections of data that were dis-
cussed in the previous section. Rather than requiring you to very specifically define exactly how you
want a query to execute, LINQ gives you the power to stay at a more abstract level. By simply defining
what you want the query to return, you leave it up to .NET and its compilers to determine the specifics
of exactly how the query will be run.
In the preceding section, you looked at the current state of object querying with today’s .NET languages.
In this section, let’s take a look at LINQ and see how using it can greatly simplify these queries, as well as
other types of queries. To do this, the samples in this section start out by simply modifying the samples

from the previous section to show you how easy LINQ makes the same tasks.
Before you get started, understand that LINQ is an extension to .NET, and because of this, is isolated in
its own set of assemblies. The base LINQ functionality is located in the new
System.Core.dll
assem-
bly. This assembly does not replace any existing framework functionality, but simply augments it.
464
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 465
Chapter 9: Querying with LINQ
Additionally, by default, projects in Visual Studio 2008 include a reference to this assembly so when
starting a new ASP.NET Web project, LINQ should be readily available to you.
Basic LINQ Queries and Projections
In order to start modifying the prior sections samples to using LINQ queries, you first need to add the
LINQ namespace to the Web page, as shown in Listing 9-5.
Listing 9-5: Adding the LINQ namespace
<%@ Import Namespace="System.Linq" %>
Adding this namespace gives the page access to all of the basic LINQ functionality. If you are using
the code-behind development model, then the LINQ namespace should already be included in your
code-behind class.
Note that the default web.config file included with a Visual Basic Web site already includes the Sys-
tem.Linq namespace declaration in it, so if you are using this type of project you do not need to manually
add the namespace.
Next, you can start by modifying code from Listing 9-2. If you remember, this basic sample
simply generates a generic List of movies and binds the list to a GridView control. Listing 9-6 shows
how the code can be modified to use LINQ to query the movies list and bind the resultset to the
GridView.
Listing9-6:CreatingaquerywithLINQ
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim movies = GetMovies()

Dim query = From m In movies _
Select m
Me.GridView1.DataSource = query
Me.GridView1.DataBind()
End Sub
C#
protected void Page_Load(object sender, EventArgs e)
{
var movies = GetMovies();
var query = from m in movies
select m;
this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
If we deconstruct the code sample, there are three basic actions happening. First, the code uses the
Get-
Movies()
method to obtain the generic
List
<
Movie
> collection.
465

×