Overview
The application you’ll be building in these tutorials is a simple university website.Users can view and update student, course, and instructor information. A few of the screens you'll create are shown below.
Creating the Web Application
To start the tutorial, open Visual Studio and then create a new ASP.NET Web Application Project using the ASP.NET Web Application template:This template creates a web application project that already includes a style sheet and master pages:
Open the Site.Master file and change "My ASP.NET Application" to “Contoso University”.
<h1>
Contoso University</h1>
Find the Menu control named NavigationMenu
and replace it with the following markup, which adds menu items for the pages you'll be creating.<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false" IncludeStyleBlock="false" Orientation="Horizontal"> <Items> <asp:MenuItem NavigateUrl="~/Default.aspx" Text="Home" /> <asp:MenuItem NavigateUrl="~/About.aspx" Text="About" /> <asp:MenuItem NavigateUrl="~/Students.aspx" Text="Students"> <asp:MenuItem NavigateUrl="~/StudentsAdd.aspx" Text="Add Students" /> </asp:MenuItem> <asp:MenuItem NavigateUrl="~/Courses.aspx" Text="Courses"> <asp:MenuItem NavigateUrl="~/CoursesAdd.aspx" Text="Add Courses" /> </asp:MenuItem> <asp:MenuItem NavigateUrl="~/Instructors.aspx" Text="Instructors"> <asp:MenuItem NavigateUrl="~/InstructorsCourses.aspx" Text="Course Assignments" /> <asp:MenuItem NavigateUrl="~/OfficeAssignments.aspx" Text="Office Assignments" /> </asp:MenuItem> <asp:MenuItem NavigateUrl="~/Departments.aspx" Text="Departments"> <asp:MenuItem NavigateUrl="~/DepartmentsAdd.aspx" Text="Add Departments" /> </asp:MenuItem> </Items> </asp:Menu>Open the Default.aspx page and change the
Content
control named BodyContent
to this:<asp:Content ID="BodyContent" runat="server"
ContentPlaceHolderID="MainContent">
<h2>
Welcome to Contoso University!
</h2>
</asp:Content>
You now have a simple home page with links to the various pages that you'll be creating:Creating the Database
For these tutorials, you'll use the Entity Framework data model designer to automatically create the data model based on an existing database (often called the database-first approach). An alternative that's not covered in this tutorial series is to create the data model manually and then have the designer generate scripts that create the database (the model-first approach).For the database-first method used in this tutorial, the next step is to add a database to the site. The easiest way is to first download the project that goes with this tutorial. Then right-click the App_Data folder, select Add Existing Item, and select the School.mdf database file from the downloaded project.
An alternative is to follow the instructions at Creating the School Sample Database. Whether you download the database or create it, copy the School.mdf file from the following folder to your application's App_Data folder:
%PROGRAMFILES%\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA
(This location of the .mdf file assumes you're using SQL Server 2008 Express.)
If you create the database from a script, perform the following steps to create a database diagram:
-
In Server Explorer, expand Data Connections, expand School.mdf, right-click Database Diagrams, and select Add New Diagram.
-
Select all of the tables and then click Add.
SQL Server creates a database diagram that shows tables, columns in the tables, and relationships between the tables. You can move the tables around to organize them however you like.
-
Save the diagram as "SchoolDiagram" and close it.
The diagram looks something like this (the tables might be in different locations from what's shown here):
Creating the Entity Framework Data Model
Now you can create an Entity Framework data model from this database. You could create the data model in the root folder of the application, but for this tutorial you'll place it in a folder named DAL (for Data Access Layer).In Solution Explorer, add a project folder named DAL (make sure it's under the project, not under the solution).
Right-click the DAL folder and then select Add and New Item. Under Installed Templates, select Data, select the ADO.NET Entity Data Model template, name it SchoolModel.edmx, and then click Add.
This starts the Entity Data Model Wizard. In the first wizard step, the Generate from database option is selected by default. Click Next.
In the Choose Your Data Connection step, leave the default values and click Next. The School database is selected by default and the connection setting is saved in the Web.config file as SchoolEntities.
In the Choose Your Database Objects wizard step, select all of the tables except
sysdiagrams
(which was created for the diagram you generated earlier) and then click Finish.After it's finished creating the model, Visual Studio shows you a graphical representation of the Entity Framework objects (entities) that correspond to your database tables. (As with the database diagram, the location of individual elements might be different from what you see in this illustration. You can drag the elements around to match the illustration if you want.)
Exploring the Entity Framework Data Model
You can see that the entity diagram looks very similar to the database diagram, with a couple of differences. One difference is the addition of symbols at the end of each association that indicate the type of association (table relationships are called entity associations in the data model):-
A one-to-zero-or-one association is represented by "1" and "0..1".
In this case, aPerson
entity may or may not be associated with anOfficeAssignment
entity. AnOfficeAssignment
entity must be associated with aPerson
entity. In other words, an instructor may or may not be assigned to an office, and any office can be assigned to only one instructor.
-
A one-to-many association is represented by "1" and "*".
In this case, aPerson
entity may or may not have associatedStudentGrade
entities. AStudentGrade
entity must be associated with onePerson
entity.StudentGrade
entities actually represent enrolled courses in this database; if a student is enrolled in a course and there's no grade yet, theGrade
property is null. In other words, a student may not be enrolled in any courses yet, may be enrolled in one course, or may be enrolled in multiple courses. Each grade in an enrolled course applies to only one student.
-
A many-to-many association is represented by "*" and "*".
In this case, aPerson
entity may or may not have associatedCourse
entities, and the reverse is also true: aCourse
entity may or may not have associatedPerson
entities. In other words, an instructor may teach multiple courses, and a course may be taught by multiple instructors. (In this database, this relationship applies only to instructors; it does not link students to courses. Students are linked to courses by the StudentGrades table.)
Courses
property in a Person
entity contains a collection of all the Course
entities that are related to that Person
entity.Yet another difference between the database and data model is the absence of the
CourseInstructor
Person
and Course
tables in a many-to-many relationship. The navigation properties enable you to get related Course
entities from the Person
entity and related Person
entities from the Course
entity, so there's no need to represent the association table in the data model. association table that's used in the database to link the For purposes of this tutorial, suppose the
FirstName
column of the Person
table actually contains both a person's first name and middle name. You
want to change the name of the field to reflect this, but the database
administrator (DBA) might not want to change the database. You can
change the name of the FirstName
property in the data model, while leaving its database equivalent unchanged.In the designer, right-click FirstName in the
Person
entity, and then select Rename.Type in the new name "FirstMidName". This changes the way you refer to the column in code without changing the database.
The model browser provides another way to view the database structure, the data model structure, and the mapping between them. To see it, right-click a blank area in the entity designer and then click Model Browser.
The Model Browser pane displays a tree view. (The Model Browser pane might be docked with the Solution Explorer pane.) The SchoolModel node represents the data model structure, and the SchoolModel.Store node represents the database structure.
Expand SchoolModel.Store to see the tables, expand Tables / Views to see tables, and then expand Course to see the columns within a table.
Expand SchoolModel, expand Entity Types, and then expand the Course node to see the entities and the properties within the entities.
In either the designer or the Model Browser pane you can see how the Entity Framework relates the objects of the two models. Right-click the
Person
entity and select Table Mapping.This opens the Mapping Details window. Notice that this window lets you see that the database column
FirstName
is mapped to FirstMidName
, which is what you renamed it to in the data model.The Entity Framework uses XML to store information about the database, the data model, and the mappings between them. The SchoolModel.edmx file is actually an XML file that contains this information. The designer renders the information in a graphical format, but you can also view the file as XML by right-clicking the .edmx file in Solution Explorer, clicking Open With, and selecting XML (Text) Editor. (The data model designer and an XML editor are just two different ways of opening and working with the same file, so you cannot have the designer open and open the file in an XML editor at the same time.)
You've now created a website, a database, and a data model. In the next walkthrough you'll begin working with data using the data model and the ASP.NET
EntityDataSource
control.==============================================
Part 2
The EntityDataSource Control
In the previous tutorial you created a web site, a database, and a data model. In this tutorial you work with theEntityDataSource
control that ASP.NET provides in order to make it easy to work with an Entity Framework data model. You'll create a GridView
control for displaying and editing student data, a DetailsView
control for adding new students, and a DropDownList
control for selecting a department (which you'll use later for displaying associated courses). Note that in this application you won't be adding input validation to pages that update the database, and some of the error handling will not be as robust as would be required in a production application. That keeps the tutorial focused on the Entity Framework and keeps it from getting too long. For details about how to add these features to your application, see Validating User Input in ASP.NET Web Pages and Error Handling in ASP.NET Pages and Applications.
Adding and Configuring the EntityDataSource Control
You'll begin by configuring anEntityDataSource
control to read Person
entities from the People
entity set.Make sure you have Visual Studio open and that you're working with the project you created in part 1. If you haven't built the project since you created the data model or since the last change you made to it, build the project now. Changes to the data model are not made available to the designer until the project is built.
Create a new web page using the Web Form using Master Page template, and name it Students.aspx.
Specify Site.Master as the master page. All of the pages you create for these tutorials will use this master page.
In Source view, add an
h2
heading to the Content
control named Content2
, as shown in the following example:<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
</asp:Content>
From the Data tab of the Toolbox, drag an EntityDataSource
control to the page, drop it below the heading, and change the ID to StudentsEntityDataSource
:<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server">
</asp:EntityDataSource>
</asp:Content>
Switch to Design view, click the data source control's smart tag, and then click Configure Data Source to launch the Configure Data Source wizard.In the Configure ObjectContext wizard step, select SchoolEntities as the value for Named Connection, and select SchoolEntities as the DefaultContainerName value. Then click Next.
Note: If you get the following dialog box at this point, you have to build the project before proceeding.
In the Configure Data Selection step, select People as the value for EntitySetName. Under Select, make sure the Select All check box is selected. Then select the options to enable update and delete. When you're done, click Finish.
Configuring Database Rules to Allow Deletion
You'll be creating a page that lets users delete students from thePerson
table, which has three relationships with other tables (Course
, StudentGrade
, and OfficeAssignment
). By default, the database will prevent you from deleting a row in Person
if there are related rows in one of the other tables. You can manually
delete the related rows first, or you can configure the database to
delete them automatically when you delete a Person
row. For
student records in this tutorial, you'll configure the database to
delete the related data automatically. Because students can have related
rows only in the StudentGrade
table, you need to configure only one of the three relationships.If you're using the School.mdf file that you downloaded from the project that goes with this tutorial, you can skip this section because these configuration changes have already been done. If you created the database by running a script, configure the database by performing the following procedures.
In Server Explorer, open the database diagram that you created in part 1. Right-click the relationship between
Person
and StudentGrade
(the line between tables), and then select Properties.In the Properties window, expand INSERT and UPDATE Specification and set the DeleteRuleCascade. property to
Save and close the diagram. If you're asked whether you want to update the database, click Yes.
To make sure that the model keeps entities that are in memory in sync with what the database is doing, you must set corresponding rules in the data model. Open SchoolModel.edmx, right-click the association line between
Person
and StudentGrade
, and then select Properties.In the Properties window, set End1 OnDelete to Cascade.
Save and close the SchoolModel.edmx file, and then rebuild the project.
In general, when the database changes, you have several choices for how to sync up the model:
- For certain kinds of changes (such as adding or refreshing tables, views, or stored procedures), right-click in the designer and select Update Model from Database to have the designer make the changes automatically.
- Regenerate the data model.
- Make manual updates like this one.
FirstName
to FirstMidName
).Using a GridView Control to Read and Update Entities
In this section you'll use aGridView
control to display, update, or delete students. Open or switch to Students.aspx and switch to Design view. From the Data tab of the Toolbox, drag a
GridView
control to the right of the EntityDataSource
control, name it StudentsGridView
, click the smart tag, and then select StudentsEntityDataSource as the data source.Click Refresh Schema (click Yes if you're prompted to confirm), then click Enable Paging, Enable Sorting, Enable Editing, and Enable Deleting.
Click Edit Columns.
In the Selected fields box, delete PersonID, LastName, and HireDate. You typically don't display a record key to users, hire date is not relevant to students, and you'll put both parts of the name in one field, so you only need one of the name fields.)
Select the FirstMidName field and then click Convert this field into a TemplateField.
Do the same for EnrollmentDate.
Click OK and then switch to Source view. The remaining changes will be easier to do directly in markup. The
GridView
control markup now looks like the following example. <asp:GridView ID="StudentsGridView" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="PersonID"
DataSourceID="StudentsEntityDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:TemplateField HeaderText="FirstMidName" SortExpression="FirstMidName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="EnrollmentDate" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
The first column after the command field is a template field that
currently displays the first name. Change the markup for this template
field to look like the following example: <asp:TemplateField HeaderText="Name" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="LastNameTextBox" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox>
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
<asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In display mode, two Label
controls display the first
and last name. In edit mode, two text boxes are provided so you can
change the first and last name. As with the Label
controls in display mode, you use Bind
and Eval
expressions exactly as you would with ASP.NET data source controls that
connect directly to databases. The only difference is that you're
specifying entity properties instead of database columns.The last column is a template field that displays the enrollment date. Change the markup for this field to look like the following example:
<asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="EnrollmentDateTextBox" runat="server" Text='<%# Bind("EnrollmentDate", "{0:d}") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="EnrollmentDateLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In both display and edit mode, the format string "{0,d}" causes the
date to be displayed in the "short date" format. (Your computer might be
configured to display this format differently from the screen images
shown in this tutorial.)Notice that in each of these template fields, the designer used a
Bind
expression by default, but you've changed that to an Eval
expression in the ItemTemplate
elements. The Bind
expression makes the data available in GridView
control properties in case you need to access the data in code. In this
page you don't need to access this data in code, so you can use Eval
, which is more efficient. For more information, see Getting your data out of the data controls. Revising EntityDataSource Control Markup to Improve Performance
In the markup for theEntityDataSource
control, remove the ConnectionString
and DefaultContainerName
attributes and replace them with a ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attribute. This is a change you should make every time you create an EntityDataSource
control, unless you need to use a connection that is different from the
one that's hard-coded in the object context class. Using the ContextTypeName
attribute provides the following benefits:- Better performance. When the
EntityDataSource
control initializes the data model using theConnectionString
andDefaultContainerName
attributes, it performs additional work to load metadata on every request. This isn't necessary if you specify theContextTypeName
attribute. - Lazy loading is turned on by default in generated object context classes (such as
SchoolEntities
in this tutorial) in Entity Framework 4.0. This means that navigation properties are loaded with related data automatically right when you need it. Lazy loading is explained in more detail later in this tutorial. - Any customizations that you've applied to the object context class (in this case, the
SchoolEntities
EntityDataSource
control. Customizing the object context class is an advanced topic that is not covered in this tutorial series. For more information, see Extending Entity Framework Generated Types. class) will be available to controls that use the
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
EnableDelete="True" EnableUpdate="True">
</asp:EntityDataSource>
The EnableFlattening
attribute refers to a feature that
was needed in earlier versions of the Entity Framework because foreign
key columns were not exposed as entity properties. The current version
makes it possible to use foreign key associations, which means
foreign key properties are exposed for all but many-to-many
associations. If your entities have foreign key properties and no complex types, you can leave this attribute set to False
. Don't remove the attribute from the markup, because the default value is True
. For more information, see Flattening Objects (EntityDataSource).Run the page and you see a list of students and employees (you'll filter for just students in the next tutorial). The first name and last name are displayed together.
To sort the display, click a column name.
Click Edit in any row. Text boxes are displayed where you can change the first and last name.
The Delete button also works. Click delete for a row that has an enrollment date and the row disappears. (Rows without an enrollment date represent instructors and you may get a referential integrity error. In the next tutorial you'll filter this list to include just students.)
Displaying Data from a Navigation Property
Now suppose you want to know how many courses each student is enrolled in. The Entity Framework provides that information in theStudentGrades
navigation property of the Person
entity. Because the database design does not allow a student to be
enrolled in a course without having a grade assigned, for this tutorial
you can assume that having a row in the StudentGrade
table row that is associated with a course is the same as being enrolled in the course. (The Courses
navigation property is only for instructors.)When you use the
ContextTypeName
attribute of the EntityDataSource
control, the Entity Framework automatically retrieves information for a
navigation property when you access that property. This is called lazy loading.
However, this can be inefficient, because it results in a separate call
to the database each time additional information is needed. If you need
data from the navigation property for every entity returned by the EntityDataSource
control, it's more efficient to retrieve the related data along with
the entity itself in a single call to the database. This is called eager loading, and you specify eager loading for a navigation property by setting the Include
property of the EntityDataSource
control.In Students.aspx, you want to show the number of courses for every student, so eager loading is the best choice. If you were displaying all students but showing the number of courses only for a few of them (which would require writing some code in addition to the markup), lazy loading might be a better choice.
Open or switch to Students.aspx, switch to Design view, select
StudentsEntityDataSource
, and in the Properties window set the Include property to StudentGrades. (If you wanted to get multiple navigation properties, you could specify their names separated by commas — for example, StudentGrades, Courses.)Switch to Source view. In the
StudentsGridView
control, after the last asp:TemplateField
element, add the following new template field: <asp:TemplateField HeaderText="Number of Courses">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("StudentGrades.Count") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In the Eval
expression, you can reference the navigation property StudentGrades
. Because this property contains a collection, it has a Count
property that you can use to display the number of courses in which the
student is enrolled. In a later tutorial you'll see how to display data
from navigation properties that contain single entities instead of
collections. (Note that you cannot use BoundField
elements to display data from navigation properties.)Run the page and you now see how many courses each student is enrolled in.
Using a DetailsView Control to Insert Entities
The next step is to create a page that has aDetailsView
control that will let you add new students. Close the browser and then create a new web page using the Site.Master master page. Name the page StudentsAdd.aspx, and then switch to Source view.Add the following markup to replace the existing markup for the
Content
control named Content2
:<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add New Students</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EnableInsert="True" EntitySetName="People">
</asp:EntityDataSource>
<asp:DetailsView ID="StudentsDetailsView" runat="server"
DataSourceID="StudentsEntityDataSource" AutoGenerateRows="False"
DefaultMode="Insert">
<Fields>
<asp:BoundField DataField="FirstMidName" HeaderText="First Name"
SortExpression="FirstMidName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name"
SortExpression="LastName" />
<asp:BoundField DataField="EnrollmentDate" HeaderText="Enrollment Date"
SortExpression="EnrollmentDate" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
</asp:Content>
This markup creates an EntityDataSource
control that is similar to the one you created in Students.aspx, except it enables insertion. As with the GridView
control, the bound fields of the DetailsView
control are coded exactly as they would be for a data control that
connects directly to a database, except that they reference entity
properties. In this case, the DetailsView
control is used only for inserting rows, so you have set the default mode to Insert
. Run the page and add a new student.
Nothing will happen after you insert a new student, but if you now run Students.aspx, you'll see the new student information.
Displaying Data in a Drop-Down List
In the following steps you'll databind aDropDownList
control to an entity set using an EntityDataSource
control. In this part of the tutorial, you won't do much with this
list. In subsequent parts, though, you'll use the list to let users
select a department to display courses associated with the department.Create a new web page named Courses.aspx. In Source view, add a heading to the
Content
control that's named Content2
:<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Courses by Department</h2>
</asp:Content>
In Design view, add an EntityDataSource
control to the page as you did before, except this time name it DepartmentsEntityDataSource
. Select Departments as the EntitySetName value, and select only the DepartmentID and Name properties.From the Standard tab of the Toolbox, drag a
DropDownList
control to the page, name it DepartmentsDropDownList
, click the smart tag, and select Choose Data Source to start the DataSource Configuration Wizard.In the Choose a Data Source step, select DepartmentsEntityDataSource as the data source, click Refresh Schema, and then select Name as the data field to display and DepartmentID as the value data field. Click OK.
The method you use to databind the control using the Entity Framework is the same as with other ASP.NET data source controls except you're specifying entities and entity properties.
Switch to Source view and add "Select a department:" immediately before the
DropDownList
control. Select a department:
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="EntityDataSource1" DataTextField="Name"
DataValueField="DepartmentID">
</asp:DropDownList>
As a reminder, change the markup for the EntityDataSource
control at this point by replacing the ConnectionString
and DefaultContainerName
attributes with a ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attribute. It's often best to wait until after you've created the
data-bound control that is linked to the data source control before you
change the EntityDataSource
control markup, because after you make the change, the designer will not provide you with a Refresh Schema option in the data-bound control.Run the page and you can select a department from the drop-down list.
This completes the introduction to using the
EntityDataSource
control. Working with this control is generally no different from
working with other ASP.NET data source controls, except that you
reference entities and properties instead of tables and columns. The
only exception is when you want to access navigation properties. In the
next tutorial you'll see that the syntax you use with EntityDataSource
control might also differ from other data source controls when you filter, group, and order data.
No comments :
Post a Comment