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

Professional ASP.NET 3.5 in C# and Visual Basic Part 53 pps

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 (392.89 KB, 10 trang )

Evjen c09.tex V2 - 01/28/2008 2:09pm Page 476
Chapter 9: Querying with LINQ
Select New With {m.Title, .Genre = g.Name}).Skip(10).Take(10)
Me.GridView1.DataSource = query
Me.GridView1.DataBind()
End Sub
C#
protected void Page_Load(object sender, EventArgs e)
{
var movies = GetMovies();
var genres = GetGenres();
var query = (from m in movies
join g in genres on m.Genre equals g.ID
select new { m.Title, g.Name }).Skip(10).Take(10);
this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
When running this code, you will see that the results start with the tenth record in the list, and only ten
records are displayed.
LINQ to XML
The second flavor of LINQ is called LINQ to XML (or XLINQ). As the name implies, LINQ to XML
enables you to use the same basic LINQ syntax to query XML documents. As with the basic LINQ fea-
tures, the LINQ to XML features of .NET are included as an extension to the basic .NET framework, and
do not change any existing functionality. Also, as with the core LINQ features, the LINQ to XML features
are contained in their own separate assembly, the System.Xml.Linq assembly.
In this section, to show how you can use LINQ to query XML, we use the same basic Movie data as in
the previous section, but converted to XML. Listing 9-18 shows a portion of the Movie data converted to
a simple XML document. The XML file containing the complete set of converted data can be found in the
downloadable code for this chapter.
Listing 9 -18: Sample Movies XML data file
<?xml version="1.0" encoding="utf-8" ?>


<Movies>
<Movie>
<Title>Shrek</Title>
<Director>Andrew Adamson</Director>
<Genre>0</Genre>
<ReleaseDate>5/16/2001</ReleaseDate>
<RunTime>89</RunTime>
</Movie>
<Movie>
<Title>Fletch</Title>
<Director>Michael Ritchie</Director>
<Genre>0</Genre>
<ReleaseDate>5/31/1985</ReleaseDate>
476
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 477
Chapter 9: Querying with LINQ
<RunTime>96</RunTime>
</Movie>
<Movie>
<Title>Casablanca</Title>
<Director>Michael Curtiz</Director>
<Genre>1</Genre>
<ReleaseDate>1/1/1942</ReleaseDate>
<RunTime>102</RunTime>
</Movie>
</Movies>
To get started seeing how you can use LINQ to XML to query XML documents, let’s walk through some
of the same basic queries we started with in the previous section. Listing 9-19 demonstrates a simple
selection query using LINQ to XML.
Listing 9 -19: Querying the XML Data file using LINQ

VB
<%@ Page Language="VB" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim query = From m In XElement.Load(MapPath("Movies.xml")).Elements("Movie") _
Select m
Me.GridView1.DataSource = query
Me.GridView1.DataBind()
End Sub
</script>
<html xmlns=" /><head runat="server">
<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 query = from m in XElement.Load(MapPath("Movies.xml")).Elements("Movie")
select m;
this.GridView1.DataSource = query;
this.GridView1.DataBind();

}
</script>
477
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 478
Chapter 9: Querying with LINQ
Notice that in this query, you tell LINQ directly where to load the XML data from, and from which
elements in that document it should retrieve the data, which in this case are all of the Movie elements.
Other than that minor change, the LINQ query is identical to queries we have seen previously.
When you execute this code, you get a page that looks like Figure 9-6.
Figure 9-6 LINQ to XML raw query results
Notice that the fields included in the resultset of the query don’t really show the node data as you might
have expected, with each child node as a separate Field in the GridView. This is because the query used
in the Listing returns a collection of generic XElement objects, not Movie objects as you might have
expected. This is because by itself, LINQ has no way of identifying what object type each node should be
mapped to. Thankfully, you can add a bit of mapping logic to the query to tell it to map each node to a
Movie object, and how the nodes sub-elements should map to the properties of the Movie object. This is
shown in Listing 9-20.
Listing 9-20: Mapping XML elements using LINQ
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim query = From m In XElement.Load(MapPath("Movies.xml")).Elements("Movie") _
Select New Movie With { _
.Title = CStr(m.Element("Title")), _
.Director = CStr(m.Element("Director")), _
.Genre = CInt(m.Element("Genre")), _
.ReleaseDate = CDate(m.Element
("ReleaseDate")), _
.Runtime = CInt(m.Element("Runtime")) _
}
Me.GridView1.DataSource = query

Me.GridView1.DataBind()
End Sub
C#
protected void Page_Load(object sender, EventArgs e)
478
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 479
Chapter 9: Querying with LINQ
{
var query = from m in XElement.Load(MapPath("Movies.xml")).Elements("Movie")
select new Movie {
Title = (string)m.Element("Title"),
Director = (string)m.Element("Director"),
Genre = (int)m.Element("Genre"),
ReleaseDate = (DateTime)m.Element("ReleaseDate"),
RunTime = (int)m.Element("RunTime")
};
this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
As you can see, we have modified the query to include mapping logic so that LINQ knows what our
actual intentions are — to create a resultset that contains the values of the Movie elements inner nodes.
Running this code now results in a GridView that contains what we want, as shown in Figure 9-7.
Figure 9-7 LINQ to XML query with the data properly mapped to a Movie object
Note that the XElements
Load
method attempts to load the entire XML document; therefore, it is not a
good idea to try to load very large XML files using this method.
Joining XML Data
LINQ to XML supports all of the same query filtering and grouping operations as LINQ to Objects. It
also supports joining data, and can actually union together data from two different XML documents — a

task that previously would have been quite difficult. Let’s look at the same basic join scenario as was
presented in the LINQ to objects section. Again, our basic XML data includes only an ID value for the
Genre. It would, however, be better to show the actual Genre name with our resultset.
479
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 480
Chapter 9: Querying with LINQ
In the case of the XML data, rather than being kept in a separate List, the Genre data is actually stored in
a completed separate XML file, showing in Listing 9-21.
Listing 9-21: Genres XML data
<?xml version="1.0" encoding="utf-8" ?>
<Genres>
<Genre>
<ID>0</ID>
<Name>Comedy</Name>
</Genre>
<Genre>
<ID>1</ID>
<Name>Drama</Name>
</Genre>
<Genre>
<ID>2</ID>
<Name>Action</Name>
</Genre>
</Genres>
To join the data together, you can use a very similar join query to that used in Listing 9-16. This is shown
in Listing 9-22.
Listing 9 -22: Joining XML data using LINQ
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim query = From m In XElement.Load(MapPath("Listing9-18.xml"))

.Elements("Movie") _
Join g In XElement.Load(MapPath("Listing9-21.xml")).Elements
("Genre") _
On CInt(m.Element("Genre")) Equals CInt(g.Element("ID")) _
Select New With { _
.Title = CStr(m.Element("Title")), _
.Director = CStr(m.Element("Director")), _
.Genre = CStr(g.Element("Name")), _
.ReleaseDate = CDate(m.Element("ReleaseDate")), _
.Runtime = CInt(m.Element("RunTime")) _
}
Me.GridView1.DataSource = query
Me.GridView1.DataBind()
End Sub
C#
protected void Page_Load(object sender, EventArgs e)
{
var query = from m in XElement.Load(MapPath("Movies.xml")).Elements("Movie")
join g in XElement.Load(MapPath("Genres.xml")).Elements("Genre")
on (int)m.Element("Genre") equals (int)g.Element("ID")
select new {
480
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 481
Chapter 9: Querying with LINQ
Title = (string)m.Element("Title"),
Director = (string)m.Element("Director"),
Genre = (string)g.Element("Name"),
ReleaseDate = (DateTime)m.Element("ReleaseDate"),
RunTime = (int)m.Element("RunTime")
};

this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
In this sample, you can see we are using the
XElement.Load
method as part of the LINQ join statement
to tell LINQ where to load the Genre data from. Once the data is joined, you can access the elements of
the Genre data as you can the elements of the movie data.
LINQ to SQL
LINQ to SQL is the last form of LINQ in this release of .NET. LINQ to SQL, as the name implies, enables
you to quickly and easily query SQL-based data sources, such as SQL Server 2005. As with the prior
flavors of LINQ, LINQ to SQL is an extension of .NET. Its features are located in the System.Data.Linq
assembly.
In addition to the normal Intellisense and strong type checking that every flavor of LINQ gives you,
LINQ to SQL also includes a basic Object Relation (O/R) mapper directly in Visual Studio. The O/R
mapper enables you to quickly map SQL-based data sources to CLR objects that you can then use LINQ
to query. It is the easiest way to get started using LINQ to SQL.
The O/R mapper is used by adding the new Linq to SQL Classes file to your Web site project. The Linq
to SQL File document type allows you to easily and visually create data contexts that you can then access
and query with LINQ queries. Figure 9-8 shows the Linq to SQL Classes file type in the Add New Item
dialog.
After clicking the Add New Items dialog’s OK button to add the file to your project, Visual Studio notifies
you that it wants to add the LINQ to SQL File to your Web site’s App_Code directory. By locating the file
there, the data context created by the LINQ to SQL Classes file will be accessible from anywhere in your
Web site.
Once the file has been added, Visual Studio automatically opens it in the LINQ to SQL design surface.
This is a simple Object Relation mapper design tool, enabling you to add, create, remove, and relate data
objects. As you modify objects to the design surface, LINQ to SQL is generating object classes that mirror
the structure of each of those objects. Later when you are ready to begin writing LINQ queries against the
data objects, these classes will allow Visual Studio to provide you with design-time Intellisense support,

strong typing and compile-time type checking. Because the O/R mapper is primarily designed to be
used with LINQ to SQL, it also makes it easy to create CLR object representations of SQL objects, such as
Tables, Views, and Stored Procedures.
To demonstrate using LINQ to SQL, we will use the same sample Movie data used in previous sections
of this chapter. For this section, the data is stored in a SQL Server Express database.
A c opy of this database is included in the downloadable code from the Wrox Web site (
www.wrox.com
).
481
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 482
Chapter 9: Querying with LINQ
After the design surface is open and ready, open the Visual Studio Server Explorer tool and locate the
Movies database and expand the database’s Tables folder. Drag the Movies table from the Server Explorer
onto the design surface. Notice that as soon as you drop the database table onto the design surface, it is
automatically interrogated to identify its structure. A corresponding entity class is created by the designer
and shown on the design surface.
Figure 9-8 The Add New Item dialog includes the new Linq to SQL File type
When you drop table objects onto the LINQ to SQL design surface, Visual Studio examines the entities
name and will if necessary, attempt to automatically pluralize the class names it generated. It does this in
order to help you more closely following the .NET Framework class naming standards. For example, if
you drop the Products table from the Northwind database onto the design surface, it would automatically
choose the singular name Product as the name of the generated class.
Unfortunately, while the designer generally does a pretty good job at figuring out the correct pluraliza-
tion for the class names, it’s not 100% accurate. Case in point, simply look at how it incorrectly pluralizes
the Movies table to Movy when you drop it into the design surface. Thankfully the designer also allows
you to change the name of entities on the design surface. You can do this simply by selecting the entity
on the design surface and clicking on the entities name in designer.
Once you have added the Movie entity, drag the Genres table onto the design surface. Again, Visual
Studio creates a class representation of this table (and notice it gives it the singular name Genre). Addi-
tionally, it detects an existing foreign key relationship between the Movie and Genre. Because it detects

this relationship, a dashed line is added between the two tables. The lines arrow indicates the direction
482
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 483
Chapter 9: Querying with LINQ
of the foreign key relationship that exists between the two tables. The LINQ to SQL design surface with
Movies and Genres tables added is shown in Figure 9-9.
Figure 9-9 The Movies and Genres tables after being added to the LINQ to SQL design surface
Now that you have set up your LINQ to SQL File, accessing its data context and querying its data is
simple. To start, you need to create an instance of the data context in the Web page where you will be
accessing the data, as shown in Listing 9-23.
Listing 9 -23: Creating a new Data Context
VB
<%@ Page Language="VB" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dc As New MoviesDataContext()
End Sub
</script>
<html xmlns=" />Continued
483
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 484
Chapter 9: Querying with LINQ
<head runat="server">
<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)
{
MoviesDataContext dc = new MoviesDataContext();
}
</script>
In this case you created an instance of the MoviesDataContext, which is the name of the data context class
generated by the LINQ to SQL File you added earlier.
Because the data context class is automatically generated by the LINQ to SQL file, its name will change
each time you create a new LINQ to SQL file. The name of this class is determined by appending the
name of your LINQ to SQL Class file with the DataContext suffix, so had you named your LINQ to
SQL File Northwind.dbml, the data context class would have been NorthwindDataContext.
After you have added the data context to your page, you can begin writing LINQ queries against it. As
mentioned earlier, because LINQ to SQL generated object classes mirror the structure of our database
tables, you will get Intellisense support as you write your LINQ queries. Listing 9-24 shows the same
basic Movie listing query that has been shown in prior sections.
Listing 9 -24: Querying Movie data from LINQ to SQL
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dc As New MoviesDataContext()
Dim query = From m In dc.Movies _
Select m
Me.GridView1.DataSource = query
Me.GridView1.DataBind()
End Sub

C#
protected void Page_Load(object sender, EventArgs e)
{
MoviesDataContext dc = new MoviesDataContext();
484
Evjen c09.tex V2 - 01/28/2008 2:09pm Page 485
Chapter 9: Querying with LINQ
var query = from m in dc.Movies
select m;
this.GridView1.DataSource = query;
this.GridView1.DataBind();
}
As is shown in Figure 9-10, running the code generates a raw list of the Movies in our database.
Figure 9-10 Data retrieved from a basic LINQ to SQL query
Note that we did not have to write any of the database access code that would typically have been
required to create this page. LINQ has taken care of that for us, even generating the SQL query based
on our LINQ syntax. You can see the SQL that LINQ generated for the query by writing the query to the
Visual Studio output window, as shown in Listing 9-25.
Listing 9-25: Writing the LINQ to SQL query to the output window
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dc As New MoviesDataContext()
Dim query = From m In dc.Movies _
Select m
System.Diagnostics.Debug.WriteLine(query)
Me.GridView1.DataSource = query
Continued
485

×