var query = from m in XElement.LoadMapPath"Movies.xml".Elements"Movie" select new Movie { Title = stringm.Element"Title", Director = stringm.Element"Director", Genre = intm.Element"Genre
Trang 1Select 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>
Trang 2</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="http://www.w3.org/1999/xhtml">
<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>
Trang 3Notice 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)
Trang 4var 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 XElementsLoadmethod 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
Trang 5In 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 {
Trang 6Title = (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 theXElement.Loadmethod 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 copy of this database is included in the downloadable code from the Wrox Web site (www.wrox.com).
Trang 7After 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
Trang 8of 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="http://www.w3.org/1999/xhtml">
Continued
Trang 9<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();
Trang 10var 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