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

ASP.NET 4 Unleased - p 100 pdf

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

ptg
964
CHAPTER 20 Data Access with LINQ to SQL
Performing Standard Database Commands with
LINQ to SQL
In this section, you learn how to use LINQ to SQL as a replacement for working directly
with SQL. We start by discussing how LINQ to SQL queries differ from standard LINQ
queries. Next, we examine how you can perform standard database queries and commands
using LINQ to SQL such as Select, Update, Insert, and Delete commands. We’ll also discuss
how you can create dynamic queries with LINQ. Finally, we investigate the important
topic of how you can debug LINQ to SQL queries.
LINQ to Objects Versus LINQ to SQL
You can use standard LINQ (LINQ to Objects) with any object that implements the
IEnumerable<T> interface interface>. You can use LINQ to SQL, on the other hand, with
any object that implements the IQueryable<T> interface. Standard LINQ is implemented
with the extension methods exposed by the System.Linq.Enumerable class. LINQ to SQL,
on the other hand, uses the extension methods exposed by the System.Linq.Queryable
class. Why the difference?
When you build a query using standard LINQ, the query executes immediately. When you
build a query using LINQ to SQL, on the hand, the query does not execute until you start
enumerating the results. In other words, the query doesn’t execute until you use a foreach
loop to walk through the query results.
Consider the following valid LINQ to SQL query:
var query = tMovie.Where(m => m.Director == “Steven Spielberg”)
.OrderBy( m => m.BoxOfficeTotals )
.Select( m => m.Title );
This query returns a list of movies directed by Steven Spielberg in order of the movie box
office totals. You want LINQ to SQL to execute this query against the database in the most
efficient way possible. In particular, you don’t want LINQ to SQL to execute each method
independently; you want LINQ to SQL to execute one smart database query.
When executing this query, it would be bad if LINQ to SQL (1) grabbed all the Movie


records that were directed by Steven Spielberg; (2) sorted the records; and then (3)
discarded all the columns except the Title column. You want LINQ to SQL to perform one
smart database query that looks like this:
SELECT [t0].[Title] FROM [Movie] AS [t0] WHERE [t0].[Director] = @p0
ORDER BY [t0].[BoxOfficeTotals]
This SQL query is the exact query that LINQ to SQL performs. LINQ to SQL defers execu-
tion of a query until you start iterating through the results of the query. When you build a
query, you are in reality building a representation of the query. Technically, you are build-
ing an expression tree. That way, LINQ to SQL can translate the query into one efficient
SQL statement when it comes time to actually execute it.
From the Library of Wow! eBook
ptg
965
Performing Standard Database Commands with LINQ to SQL
To summarize, when you build a query using standard LINQ, the query executes as you
build it. When you build a query using LINQ to SQL, you are building a representation of
a query that doesn’t actually execute until you start iterating through the query’s results.
NOTE
When people first start using LINQ, they always worry about how they can build the
equivalent of dynamic SQL commands. Later in this section, you learn how to create
dynamic LINQ to SQL queries by dynamically building expression trees.
Selecting with LINQ to SQL
If you want to perform a simple, unordered select, you can use the following query
(assuming that you have an entity named Movie that represents the Movies database table):
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies;
No LINQ extension methods are used in this query. All the items are retrieved from the
Movies table. If you prefer, you can use query syntax instead of method syntax, like this:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = from m in db.Movies select m;

Selecting Particular Columns
If you want to select only particular columns, and not all the columns, from a database
table, you can create an anonymous type on-the-fly, like this:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies.Select( m => new {m.Id, m.Title} );
The expression new {m.Id, m.Title} creates an anonymous type that has two properties:
Id and Title. The names of the properties of the anonymous type are inferred. If you
want to be more explicit, or if you want to change the names of the anonymous type’s
properties, you can construct your query like this:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies.Select( m => new {Id = m.Id, MovieTitle = m.Title} );
Selecting Particular Rows
If you want to select only particular rows from a database table and not all the rows, you
can take advantage of the Where() method. The following LINQ to SQL query retrieves all
the movies directed by George Lucas with box office totals greater than $100,000:
20
From the Library of Wow! eBook
ptg
966
CHAPTER 20 Data Access with LINQ to SQL
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies
.Where( m => m.Director == “George Lucas” && m.BoxOfficeTotals > 100000.00m)
.Select( m => new {m.Title, m.Director, m.BoxOfficeTotals});
Remember to always call the Where() method before the Select() method. You need to
filter your data with Where() before you shape it with Select().
Selecting Rows in a Particular Order
You can use the following methods to control the order in which rows are returned from a
LINQ to SQL query:
. OrderBy()—Returns query results in a particular ascending order.

. OrderByDescending()—Returns query results in a particular descending order.
. ThenBy()—Returns query results using in an additional ascending order.
. ThenByDescending()—Returns query results using an additional descending order.
The OrderBy() and OrderBy() methods return an IOrderedQueryable<T> collection
instead of the normal IQueryable<T> collection type collection type>. If you want to
perform additional sorting, you need to call either the ThenBy() or ThenByDescending()
method.
The following query returns movies in order of release date and then in order of box
office totals:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies.OrderBy(m=>m.DateReleased).ThenBy(m=>m.BoxOfficeTotals);
Executing this LINQ to SQL query executes the following SQL query:
SELECT
[t0].[Id],
[t0].[CategoryId],
[t0].[Title],
[t0].[Director],
[t0].[DateReleased],
[t0].[InTheaters],
[t0].[BoxOfficeTotals],
[t0].[Description]
FROM [dbo].[Movie] AS [t0]
ORDER BY [t0].[DateReleased], [t0].[BoxOfficeTotals]
Selecting a Single Row
If you want to select a single row from the database, you can use one of the following two
query methods:
From the Library of Wow! eBook
ptg
967
Performing Standard Database Commands with LINQ to SQL

. Single()—Selects a single record.
. SingleOrDefault()—Selects a single record or a default instance.
The first method assumes there is at least one element to be returned. (If not, you get an
exception.) The second method returns null (for a reference type) when no matching
element is found.
Here’s a sample query that retrieves the only record where the movie Id has the value 1:
MyDatabaseDataContext db = new MyDatabaseDataContext();
Movie result = db.Movies.SingleOrDefault(m => m.Id == 1);
if (result != null)
Response.Write(result.Title);
This query returns a single object of type Movie. If there is no movie record that matches
the query, result is null, and the value of the Movie Title property is not written.
NOTE
When you execute a query that returns a single result, there is no deferred query exe-
cution. The LINQ query is translated into a SQL command and executed immediately.
Performing a LIKE Select
You can perform the equivalent of a LIKE Select with LINQ to SQL in several ways. First,
you can use String methods such as Length, Substring, Contains, StartsWith, EndsWith,
IndexOf, Insert, Remove, Replace, Trim, ToLower, ToUpper, LastIndexOf, PadRight, and
PadLeft with LINQ to SQL queries. For example, the following query returns all movies
that start with the letter t:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies.Where(m=>m.Title.StartsWith(“t”));
Behind the scenes, this query is translated into a SQL query that uses the LIKE operator:
SELECT [t0].[Id], [t0].[CategoryId], [t0].[Title], [t0].[Director],
[t0].[DateReleased], [t0].[InTheaters], [t0].[BoxOfficeTotals], [t0].[Description]
FROM [dbo].[Movie] AS [t0]
WHERE [t0].[Title] LIKE @p0
An alternative, more flexible way to make LIKE queries is to use the
System.Data.Linq.SqlClient.SqlMethods.Like() method:

MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.Movies.Where(m=>SqlMethods.Like(m.Title, “t%”));
Using the SqlMethods.Like() method is more flexible than using the standard String
methods because you can add as many wildcards to the match pattern as you need.
20
From the Library of Wow! eBook
ptg
968
CHAPTER 20 Data Access with LINQ to SQL
NOTE
The SqlMethods class also contains a number of useful methods for expressing the
SQL DateDiff() function in a LINQ to SQL Query.
Paging Through Records
Doing database paging right when working with ADO.NET is difficult. The SQL language
is not designed to make it easy to retrieve a range of records. Doing database paging using
LINQ to SQL queries, on the other hand, is trivial.
You can take advantage of the following two query methods to perform database paging:
. Skip()—Enables you to skip a certain number of records.
. Take()—Enables you to take a certain number of records.
For example, the class in Listing 20.18 contains a method named SelectedPaged() that
gets a particular page of movie records from the Movie database table.
LISTING 20.18 Standard\App_Code\Movie.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
public partial class Movie
{
public static IEnumerable<Movie> Select()
{

MyDatabaseDataContext db = new MyDatabaseDataContext();
return db.Movies;
}
public static IEnumerable< Movie> SelectPaged
(
int startRowIndex,
int maximumRows
)
{
return Select().Skip(startRowIndex).Take(maximumRows);
}
public static int SelectCount()
{
From the Library of Wow! eBook
ptg
969
Performing Standard Database Commands with LINQ to SQL
return Select().Count();
}
}
I’m assuming, in the case of Listing 20.18, that you have already created a Movie entity by
using the LINQ to SQL Designer. The Movie class in Listing 20.18 is a partial class that
extends the existing Movie class generated by the Designer.
The ASP.NET page in Listing 20.19 illustrates how you can use the Movie class with the
ObjectDataSource control to page through movie records.
LISTING 20.19 Standard\ShowPagedMovies.aspx
<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

<html xmlns=”

<head runat=”server”>
<title>Show Paged Movies</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
AllowPaging=”true”
PageSize=”5”
Runat=”server” />
<asp:ObjectDataSource
id=”srcMovies”
TypeName=”Movie”
SelectMethod=”SelectPaged”
SelectCountMethod=”SelectCount”
EnablePaging=”true”
Runat=”server” />
</div>
</form>
</body>
</html>
20
From the Library of Wow! eBook
ptg
970
CHAPTER 20 Data Access with LINQ to SQL
Joining Records from Different Tables
You can perform joins when selecting entities just like you can when joining database

tables. For example, imagine that you want to join the Movie and MovieCategory tables
on the CategoryId key. Assuming that you have both a Movie and MovieCategory entity,
you can use the following query:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = db.MovieCategories
.Join(db.Movies, c=>c.Id, m=>m.CategoryId, (c,m)=>new {c.Id,c.Name,m.Title});
This LINQ query gets translated into the following SQL command:
SELECT [t0].[Id], [t0].[Name], [t1].[Title]
FROM [dbo].[MovieCategory] AS [t0]
INNER JOIN [dbo].[Movie] AS [t1] ON [t0].[Id] = [t1].[CategoryId]
This query performs an inner join. If you want to perform an outer join, the syntax is a
little more complicated. Here’s how you do a left outer join using query syntax:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var query = from c in db.MovieCategories
join m in db.Movies
on c.Id equals m.CategoryId into cm
from m in cm.DefaultIfEmpty()
select new { c.Id, c.Name, m.Title };
This LINQ query gets translated into the following SQL SELECT:
SELECT [t0].[Id], [t0].[Name], [t1].[Title] AS [value]
FROM [dbo].[MovieCategory] AS [t0]
LEFT OUTER JOIN [dbo].[Movie] AS [t1] ON [t0].[Id] = [t1].[CategoryId]
As an alternative to using joins, consider taking advantage of the associations between
entities. Remember that the following type of query is perfectly valid:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var category = db.MovieCategories.Single( c => c.Name == “Drama” );
var query = category.Movies;
Caching Records
Getting caching to work with LINQ to SQL is a little tricky. Remember that a LINQ to SQL
query represents a query expression and not the actual query results. The SQL command is

not executed, and the results are not retrieved until you start iterating through the query
results.
For example, imagine that you declare the following ObjectDataSource control in a page
and that this ObjectDataSource control represents a class that returns a LINQ to SQL
query:
From the Library of Wow! eBook
ptg
971
Performing Standard Database Commands with LINQ to SQL
<asp:ObjectDataSource
id=”srcMovies”
TypeName=”Movie”
SelectMethod=”Select”
EnableCaching=”true”
CacheDuration=”9999”
Runat=”server” />
This ObjectDataSource has been set up to cache its results. Its EnableCaching and
CacheDuration properties are set. However, what gets cached here is the query expression
and not that actual query results. The SQL select statement that corresponds to the LINQ
to SQL query executes every time the page is requested.
To get caching to work, we need to force the query results and not the query into the cache.
The Movie class in Listing 20.20 contains a SelectCached() method that successfully caches
database data with a LINQ to SQL query.
LISTING 20.20 Standard\App_Code\Movie.cs
using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
public partial class Movie

{
public static IEnumerable<Movie> Select()
{
MyDatabaseDataContext db = new MyDatabaseDataContext();
return db.Movies;
}
public static IEnumerable<Movie> SelectCached()
{
HttpContext context = HttpContext.Current;
List<Movie> movies = (List<Movie>)context.Cache[“Movies”];
if (movies == null)
{
movies = Select().ToList();
context.Cache[“Movies”] = movies;
context.Trace.Warn(“Retrieving movies from database”);
}
return movies;
}
}
20
From the Library of Wow! eBook
ptg
972
CHAPTER 20 Data Access with LINQ to SQL
The SelectCached() method attempts to retrieve movie records from the cache. If the
records can’t be retrieved from the cache, the movies are retrieved from the database. The
vast majority of the time, the movies are retrieved from the cache.
The trick here is to use the ToList() method to convert the IEnumerable<Movie> into a
List<Movie>. When the List<Movie> is created, the SQL query associated with the LINQ
to SQL query is executed and the actual data is returned.

You can use the class in Listing 20.20 with the ASP.NET page in Listing 20.21.
LISTING 20.21 Standard\ShowCachedMovies.aspx
<%@ Page Language=”C#” Trace=”true” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

<html xmlns=”
<head runat=”server”>
<title>Show Cached Movies</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<asp:ObjectDataSource
id=”srcMovies”
TypeName=”Movie”
SelectMethod=”SelectCached”
Runat=”server” />
</div>
</form>
</body>
</html>
The ObjectDataSource in Listing 20.21 does not have caching enabled. All the caching
happens in the Data Access layer (the Movie class).
From the Library of Wow! eBook
ptg
973

Performing Standard Database Commands with LINQ to SQL
Inserting with LINQ to SQL
There are two steps to adding and inserting a new record with LINQ to SQL. First, you
need to use the InsertOnSubmit() method to add an entity to an existing table. Next, you
call SubmitChanges() on the DataContext to execute the SQL INSERT statement against the
database.
The class in Listing 20.22 illustrates how you can write a method to add a new record into
the Movie database table.
LISTING 20.22 Standard\App_Code\Movie.cs
using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
public partial class Movie
{
public static int Insert(Movie movieToInsert)
{
MyDatabaseDataContext db = new MyDatabaseDataContext();
db.Movies.InsertOnSubmit( movieToInsert );
db.SubmitChanges();
return movieToInsert.Id;
}
public static IEnumerable<Movie> Select()
{
MyDatabaseDataContext db = new MyDatabaseDataContext();
return db.Movies.OrderByDescending(m=>m.Id);
}
}
The Movie class includes an Insert() method that inserts a new movie into the database.

The Insert() method returns an integer that represents the identity value of the new
record. As soon as SubmitChanges() is called, the Id property is updated with the new
identity value from the database.
NOTE
I’m assuming in this section that you have used the LINQ to SQL Designer to create
entities for the Movie and MovieCategories database tables.
20
From the Library of Wow! eBook

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×