If, on the other hand, your database table were named Movies and your class were named Movie, you would need to supply the Name property for the Table attribute to map the correct table
Trang 1Storage—Indicates a field where the value of the property is stored
UpdateCheck—Indicates whether the property participates in optimistic concurrency
comparisons
The Table attribute supports the following single property:
Name—Indicates the name of the database table that corresponds to the class
Some comments about these attributes are needed First, you don’t need to specify a Name
property when your property or class name corresponds to your database column or table
name If, on the other hand, your database table were named Movies and your class were
named Movie, you would need to supply the Name property for the Table attribute to map
the correct table to the class
Second, you always want to specify the primary key column by using the IsPrimaryKey
property For example, if you don’t specify a primary key column, you can’t do updates
against your database using LINQ
Finally, even though we didn’t do this in our Movie class, you almost always want to
include a timestamp column in your database table and indicate the timestamp column
by using the IsVersion property If you don’t do this, LINQ to SQL checks whether the
values of all the properties match the values of all the columns before performing an
update command to prevent concurrency conflicts If you specify a version property, LINQ
to SQL can check the value of this single property against the database rather than all the
columns
Now that we’ve created an entity, we can start performing queries against the database
using LINQ to SQL For example, the page in Listing 20.12 contains a form that enables
you to search for movies by a particular director
LISTING 20.12 Entities\SearchMovies.aspx
<%@ Page Language=”C#” %>
<%@ Import Namespace=”System.Web.Configuration” %>
<%@ Import Namespace=”System.Linq” %>
<%@ Import Namespace=”System.Data.Linq” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<script runat=”server”>
protected void btnSearch_Click(object sender, EventArgs e)
{
string conString = WebConfigurationManager
ConnectionStrings[“Movies”].ConnectionString;
DataContext db = new DataContext(conString);
var tMovie = db.GetTable<Movie>();
Trang 2grdMovies.DataSource = tMovie.Where( m => m.Director.Contains(
txtDirector.Text) );
grdMovies.DataBind();
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>SearchMovies.aspx</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:Label
id=”lblDirector”
Text=”Director:”
AssociatedControlID=”txtDirector”
Runat=”server” />
<asp:TextBox
id=”txtDirector”
Runat=”server” />
<asp:Button
id=”btnSearch”
Text=”Search”
OnClick=”btnSearch_Click”
Runat=”Server” />
<br /><br />
<asp:GridView
id=”grdMovies”
Runat=”server” />
</div>
</form>
</body>
</html>
When you click the Search button, the btnSearch_Click() method executes the LINQ to
SQL query
First, a DataContext is created by passing a database connection string to the class’s
constructor The DataContext is responsible for tracking all the LINQ to SQL entities and
representing the database connection
Trang 3Next, a variable named tMovie is instantiated that represents a particular database table
from the DataContext Because we pass the Movie entity to the GetTable<T>() method()
method>, the method returns a Table<T> object that represents the Movie database table
The Table<T> object implements the IQueryable interface and can, therefore, be queried
with a LINQ to SQL query
Finally, the following LINQ to SQL query is executed:
tMovie.Where( m => m.Director.Contains(txtDirector.Text)
The lambda expression m => m.Director.Contains(txtDirector.Text) passed to the
Where() method returns every movie record from the database in which the Director
column contains the text entered into the TextBox control
We had to import two namespaces to use the LINQ to SQL query: System.Linq and
System.Data.Linq
NOTE
To keep things simple, I use the LINQ to SQL query directly within the ASP.NET page in
Listing 20.12 In real life, to avoid mixing user interface and Data Access layers, I
would perform the LINQ to SQL query in a separate class and use an
ObjectDataSource to represent the class
Building Entities with the LINQ to SQL Designer
As an alternative to building entities by hand, you can use the LINQ to SQL Designer
You can simply drag database tables from the Database Explorer (Server Explorer) onto
the Designer The Designer generates the entity classes with the correct attributes
automatically
Follow these steps to use the LINQ to SQL Designer:
1 Select Website, Add New Item to open the Add New Item dialog box
2 Select the LINQ to SQL Classes template, give it the name MyDatabase, and click the
Add button
3 When prompted to create the LINQ to SQL classes in the App_Code folder, click the
Yes button
4 After the LINQ to SQL Designer opens, drag one or more database tables from the
Database Explorer/Server Explorer window onto the Designer surface
You can view the code that the Designer generates by expanding the MyDatabase.dbml
node in the App_Code folder and double-clicking the MyDatabase.designer.cs file
The Designer generates a strongly typed DataContext class named MyDatabaseContext
Each database table that you drag onto the Designer surface gets exposed by the
DataContext class as a strongly typed property
Trang 4The Designer, furthermore, generates a distinct class for each database table you drag onto
the Designer For example, after you drag the Movie table onto the Designer, a new class
named Movie is created in the MyDatabase.designer.cs file
NOTE
The LINQ to SQL Designer attempts to pluralize table names automatically when you
add them to the Designer So, when you drag the Movie table onto the Designer, the
Designer generates a DataContext property named Movies Most of the time, but not
all of the time, it gets the pluralization right You can turn off this feature by selecting
Tools, Options and selecting the Database Tools, O/R Designer tab
The page in Listing 20.13 demonstrates how you can use the MyDatabaseContext class
when performing a LINQ to SQL query (after dragging the Movies database table onto the
LINQ to SQL Designer)
LISTING 20.13 Entities\ListMoviesByBoxOffice.aspx
<%@ Page Language=”C#” %>
<%@ Import Namespace=”System.Linq” %>
<%@ Import Namespace=”System.Data.Linq” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<script runat=”server”>
void Page_Load()
{
MyDatabaseDataContext db = new MyDatabaseDataContext();
grd.DataSource = db.Movies.OrderBy(m => m.BoxOfficeTotals);
grd.DataBind();
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>List Movies by Box Office</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grd”
runat=”server” />
Trang 5</div>
</form>
</body>
</html>
The page in Listing 20.13 displays a list of all movies in order of the movie’s box office totals
The LINQ to SQL Designer creates partial classes for each table you drag onto the Designer
surface This means that you extend the functionality of each entity by creating a new
partial class For example, the class in Listing 20.14 extends the Movie class that the LINQ
to SQL Designer generates
LISTING 20.14 Entities\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> SelectByBoxOfficeTotals()
{
return Select().OrderBy( m => m.BoxOfficeTotals);
}
}
The Movie class in Listing 20.14 is declared as a partial class It extends the partial class in
the MyDatabase.designer.cs file by adding both a Select() method and a
SelectByBoxOfficeTotals() method
NOTE
The SelectByBoxOfficeTotals() method calls the Select() method It is important
to understand that this does not cause two SQL SELECT commands to be executed
against the database Until the GridView control starts iterating through the results of
the LINQ to SQL query, you are just building an expression
Trang 6The page in Listing 20.15 demonstrates how you represent the Movie class with an
ObjectDataSource control
LISTING 20.15 Entities\PartialMovie.aspx
<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Partial Movie</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<asp:ObjectDataSource
id=”srcMovies”
TypeName=”Movie”
SelectMethod=”SelectByBoxOfficeTotals”
runat=”server” />
</div>
</form>
</body>
</html>
There is no code in the page in Listing 20.15 All the code is where it should be, in the
Data Access layer implemented by the Movie class
Building Entity Associations
One entity can be associated with another entity For example, a MovieCategory entity
might be associated with one or more Movie entities
If you have defined foreign key relationships between your database tables, these
rela-tionships are preserved when you drag your tables onto the LINQ to SQL Designer The
LINQ to SQL Designer generates entity associations based on the foreign key relationships
automatically
Trang 7For example, the MovieCategory entity is related to the Movie entity through the Movie
entity’s CategoryId property As long as you have defined a foreign key relationship
between Movie.CategoryId and MovieCategory.Id, you can use a query like this
following:
MyDatabaseDataContext db = new MyDatabaseDataContext();
var category = db.MovieCategories.Single( c => c.Name == “Drama” );
var query = category.Movies;
The second statement grabs the Drama movie category The third statement returns all
movies associated with the Drama movie category In this case, we’ve followed a
one-to-many relationship and got a list of movies that match a movie category You can also go
the opposite direction and retrieve the only movie category that matches a particular
movie:
string categoryName = db.Movies.Single(m=>m.Id==1).MovieCategory.Name;
This query retrieves the name of the movie category associated with the movie that has
an ID of 1
NOTE
Under the covers, the LINQ to SQL Designer creates the entity relationships by adding
association attributes to entity properties The LINQ to SQL Designer also adds some
tricky synchronization logic to keep the properties of associated entities synchronized
Although I wish that I could code all my entities by hand, adding all the logic necessary
to get the entity associations to work correctly is too much work For that reason, I use
the LINQ to SQL Designer
Using the LinqDataSource Control
I want to briefly describe the LinqDataSource control You can use this control to
repre-sent LINQ queries For example, the page in Listing 20.16 contains a simple search form
for searching movies by director The page uses a LinqDataSource to represent the LINQ
query
LISTING 20.16 Entities\ShowLinqDataSource.aspx
<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Show LinqDataSource</title>
</head>
<body>
Trang 8<form id=”form1” runat=”server”>
<div>
<asp:Label
id=”lblSearch”
AssociatedControlID=”txtSearch”
Text=”Search:”
Runat=”server” />
<asp:TextBox
id=”txtSearch”
Runat=”server” />
<asp:Button
id=”btnSearch”
Text=”Search”
Runat=”server” />
<br /><br />
<asp:GridView
id=”grd”
DataSourceID=”LinqDataSource1”
Runat=”server” />
<asp:LinqDataSource
ID=”LinqDataSource1”
ContextTypeName=”MyDatabaseDataContext”
TableName=”Movies”
Where=”Director == @Director”
OrderBy=”DateReleased”
Select=”new (Title, Director)”
runat=”server”>
<whereparameters>
<asp:controlparameter Name=”Director”
ControlID=”txtSearch”
PropertyName=”Text”
Type=”String” />
</whereparameters>
</asp:LinqDataSource>
</div>
</form>
</body>
</html>
Trang 9The LinqDataSource in Listing 20.16 represents the following LINQ query:
var query = db.Movies
.Where(m => m.Director == txtSearch.Text)
.OrderBy(m => m.DateReleased)
.Select(m => new {m.Title, m.Director});
You also can use the LinqDataSource to generate Update, Insert, and Delete LINQ
queries automatically Simply set the EnableInsert, EnableUpdate, or EnableDelete
property to the value True For example, the page in Listing 20.17 contains a
DetailsView control and a GridView control that you can use to insert, edit, and delete
movie records The inserting, editing, and deleting is performed by the LinqDataSource
control
LISTING 20.17 Entities\EditLinqDataSource.aspx
<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<script runat=”server”>
protected void frmMovie_ItemInserted
(
object sender,
DetailsViewInsertedEventArgs e
)
{
grdMovies.DataBind();
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Edit LinqDataSource</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:DetailsView
id=”frmMovie”
DataSourceID=”srcMovies”
DefaultMode=”Insert”
AutoGenerateRows=”false”
AutoGenerateInsertButton=”true”
Runat=”server” OnItemInserted=”frmMovie_ItemInserted”>
Trang 10<Fields>
<asp:BoundField DataField=”Title” HeaderText=”Title” />
<asp:BoundField DataField=”Director” HeaderText=”Director” />
<asp:BoundField DataField=”DateReleased” HeaderText=”Date Released” />
</Fields>
</asp:DetailsView>
<br /><br />
<asp:GridView
id=”grdMovies”
DataKeyNames=”Id”
DataSourceID=”srcMovies”
AllowPaging=”true”
PageSize=”5”
AutoGenerateEditButton=”true”
AutoGenerateDeleteButton=”true”
Runat=”server” />
<asp:LinqDataSource
id=”srcMovies”
ContextTypeName=”MyDatabaseDataContext”
TableName=”Movies”
OrderBy=”Id descending”
EnableInsert=”true”
EnableUpdate=”true”
EnableDelete=”true”
AutoPage=”true”
Runat=”server” />
</div>
</form>
</body>
</html>
One other thing that you should notice about the LinqDataSource control in Listing
20.17: the LinqDataSource control has an AutoPage attribute set to the value True
When this property has the value True, the LinqDataSource performs data source paging
automatically
I don’t use the LinqDataSource control in production applications Instead, I wrap up all
my LINQ queries in a separate class and use the ObjectDataSource control to represent
the class The LinqDataSource control is similar to the SqlDataSource control in that both
controls are great for prototyping and doing demos, but they are not appropriate controls
to use in production applications