Getting Started with Entity Framework 4.0 Database First and ASP.NET 4 Web Forms - Part 5
by Tom Dykstra
The Contoso University sample web application demonstrates how to create ASP.NET Web Forms applications using the Entity Framework 4.0 and Visual Studio 2010. For information about the tutorial series, see the first tutorial in the series
Working with Related Data, Continued
In the previous tutorial you began to use the EntityDataSource
control to work with related data. You displayed multiple levels of hierarchy and edited data in navigation properties. In this tutorial you’ll continue to work with related data by adding and deleting relationships and by adding a new entity that has a relationship to an existing entity.
You’ll create a page that adds courses that are assigned to departments. The departments already exist, and when you create a new course, at the same time you’ll establish a relationship between it and an existing department.
You’ll also create a page that works with a many-to-many relationship by assigning an instructor to a course (adding a relationship between two entities that you select) or removing an instructor from a course (removing a relationship between two entities that you select). In the database, adding a relationship between an instructor and a course results in a new row being added to the CourseInstructor
association table; removing a relationship involves deleting a row from the CourseInstructor
association table. However, you do this in the Entity Framework by setting navigation properties, without referring to the CourseInstructor
table explicitly.
Adding an Entity with a Relationship to an Existing Entity
Create a new web page named CoursesAdd.aspx that uses the Site.Master master page, and add the following markup to the Content
control named Content2
:
[!code-aspxMain]
1: <h2>Add Courses</h2>
2: <asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
3: ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
4: EntitySetName="Courses"
5: EnableInsert="True" EnableDelete="True" >
6: </asp:EntityDataSource>
7: <asp:DetailsView ID="CoursesDetailsView" runat="server" AutoGenerateRows="False"
8: DataSourceID="CoursesEntityDataSource" DataKeyNames="CourseID"
9: DefaultMode="Insert" oniteminserting="CoursesDetailsView_ItemInserting">
10: <Fields>
11: <asp:BoundField DataField="CourseID" HeaderText="ID" />
12: <asp:BoundField DataField="Title" HeaderText="Title" />
13: <asp:BoundField DataField="Credits" HeaderText="Credits" />
14: <asp:TemplateField HeaderText="Department">
15: <InsertItemTemplate>
16: <asp:EntityDataSource ID="DepartmentsEntityDataSource" runat="server" ConnectionString="name=SchoolEntities"
17: DefaultContainerName="SchoolEntities" EnableDelete="True" EnableFlattening="False"
18: EntitySetName="Departments" EntityTypeFilter="Department">
19: </asp:EntityDataSource>
20: <asp:DropDownList ID="DepartmentsDropDownList" runat="server" DataSourceID="DepartmentsEntityDataSource"
21: DataTextField="Name" DataValueField="DepartmentID"
22: oninit="DepartmentsDropDownList_Init">
23: </asp:DropDownList>
24: </InsertItemTemplate>
25: </asp:TemplateField>
26: <asp:CommandField ShowInsertButton="True" />
27: </Fields>
28: </asp:DetailsView>
This markup creates an EntityDataSource
control that selects courses, that enables inserting, and that specifies a handler for the Inserting
event. You’ll use the handler to update the Department
navigation property when a new Course
entity is created.
The markup also creates a DetailsView
control to use for adding new Course
entities. The markup uses bound fields for Course
entity properties. You have to enter the CourseID
value because this is not a system-generated ID field. Instead, it’s a course number that must be specified manually when the course is created.
You use a template field for the Department
navigation property because navigation properties cannot be used with BoundField
controls. The template field provides a drop-down list to select the department. The drop-down list is bound to the Departments
entity set by using Eval
rather than Bind
, again because you cannot directly bind navigation properties in order to update them. You specify a handler for the DropDownList
control’s Init
event so that you can store a reference to the control for use by the code that updates the DepartmentID
foreign key.
In CoursesAdd.aspx.cs just after the partial-class declaration, add a class field to hold a reference to the DepartmentsDropDownList
control:
[!code-csharpMain]
1: private DropDownList departmentDropDownList;
Add a handler for the DepartmentsDropDownList
control’s Init
event so that you can store a reference to the control. This lets you get the value the user has entered and use it to update the DepartmentID
value of the Course
entity.
[!code-csharpMain]
1: protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
2: {
3: departmentDropDownList = sender as DropDownList;
4: }
Add a handler for the DetailsView
control’s Inserting
event:
[!code-csharpMain]
1: protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
2: {
3: var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
4: e.Values["DepartmentID"] = departmentID;
5: }
When the user clicks Insert
, the Inserting
event is raised before the new record is inserted. The code in the handler gets the DepartmentID
from the DropDownList
control and uses it to set the value that will be used for the DepartmentID
property of the Course
entity.
The Entity Framework will take care of adding this course to the Courses
navigation property of the associated Department
entity. It also adds the department to the Department
navigation property of the Course
entity.
Run the page.
Enter an ID, a title, a number of credits, and select a department, then click Insert.
Run the Courses.aspx page, and select the same department to see the new course.
Working with Many-to-Many Relationships
The relationship between the Courses
entity set and the People
entity set is a many-to-many relationship. A Course
entity has a navigation property named People
that can contain zero, one, or more related Person
entities (representing instructors assigned to teach that course). And a Person
entity has a navigation property named Courses
that can contain zero, one, or more related Course
entities (representing courses that that instructor is assigned to teach). One instructor might teach multiple courses, and one course might be taught by multiple instructors. In this section of the walkthrough, you’ll add and remove relationships between Person
and Course
entities by updating the navigation properties of the related entities.
Create a new web page named InstructorsCourses.aspx that uses the Site.Master master page, and add the following markup to the Content
control named Content2
:
[!code-aspxMain]
1: <h2>Assign Instructors to Courses or Remove from Courses</h2>
2: <br />
3: <asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server"
4: ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
5: EntitySetName="People"
6: Where="it.HireDate is not null" Select="it.LastName + ', ' + it.FirstMidName AS Name, it.PersonID">
7: </asp:EntityDataSource>
8: Select an Instructor:
9: <asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsEntityDataSource"
10: AutoPostBack="true" DataTextField="Name" DataValueField="PersonID"
11: OnSelectedIndexChanged="InstructorsDropDownList_SelectedIndexChanged"
12: OnDataBound="InstructorsDropDownList_DataBound">
13: </asp:DropDownList>
14: <h3>
15: Assign a Course</h3>
16: <br />
17: Select a Course:
18: <asp:DropDownList ID="UnassignedCoursesDropDownList" runat="server"
19: DataTextField="Title" DataValueField="CourseID">
20: </asp:DropDownList>
21: <br />
22: <asp:Button ID="AssignCourseButton" runat="server" Text="Assign" OnClick="AssignCourseButton_Click" />
23: <br />
24: <asp:Label ID="CourseAssignedLabel" runat="server" Visible="false" Text="Assignment successful"></asp:Label>
25: <br />
26: <h3>
27: Remove a Course</h3>
28: <br />
29: Select a Course:
30: <asp:DropDownList ID="AssignedCoursesDropDownList" runat="server"
31: DataTextField="title" DataValueField="courseiD">
32: </asp:DropDownList>
33: <br />
34: <asp:Button ID="RemoveCourseButton" runat="server" Text="Remove" OnClick="RemoveCourseButton_Click" />
35: <br />
36: <asp:Label ID="CourseRemovedLabel" runat="server" Visible="false" Text="Removal successful"></asp:Label>
This markup creates an EntityDataSource
control that retrieves the name and PersonID
of Person
entities for instructors. A DropDrownList
control is bound to the EntityDataSource
control. The DropDownList
control specifies a handler for the DataBound
event. You’ll use this handler to databind the two drop-down lists that display courses.
The markup also creates the following group of controls to use for assigning a course to the selected instructor:
- A
DropDownList
control for selecting a course to assign. This control will be populated with courses that are currently not assigned to the selected instructor. - A
Button
control to initiate the assignment. - A
Label
control to display an error message if the assignment fails.
Finally, the markup also creates a group of controls to use for removing a course from the selected instructor.
In InstructorsCourses.aspx.cs, add a using statement:
[!code-csharpMain]
1: using ContosoUniversity.DAL;
Add a method for populating the two drop-down lists that display courses:
[!code-csharpMain]
1: private void PopulateDropDownLists()
2: {
3: using (var context = new SchoolEntities())
4: {
5: var allCourses = (from c in context.Courses
6: select c).ToList();
7:
8: var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
9: var instructor = (from p in context.People.Include("Courses")
10: where p.PersonID == instructorID
11: select p).First();
12:
13: var assignedCourses = instructor.Courses.ToList();
14: var unassignedCourses = allCourses.Except(assignedCourses.AsEnumerable()).ToList();
15:
16: UnassignedCoursesDropDownList.DataSource = unassignedCourses;
17: UnassignedCoursesDropDownList.DataBind();
18: UnassignedCoursesDropDownList.Visible = true;
19:
20: AssignedCoursesDropDownList.DataSource = assignedCourses;
21: AssignedCoursesDropDownList.DataBind();
22: AssignedCoursesDropDownList.Visible = true;
23: }
24: }
This code gets all courses from the Courses
entity set and gets the courses from the Courses
navigation property of the Person
entity for the selected instructor. It then determines which courses are assigned to that instructor and populates the drop-down lists accordingly.
Add a handler for the Assign
button’s Click
event:
[!code-csharpMain]
1: protected void AssignCourseButton_Click(object sender, EventArgs e)
2: {
3: using (var context = new SchoolEntities())
4: {
5: var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
6: var instructor = (from p in context.People
7: where p.PersonID == instructorID
8: select p).First();
9: var courseID = Convert.ToInt32(UnassignedCoursesDropDownList.SelectedValue);
10: var course = (from c in context.Courses
11: where c.CourseID == courseID
12: select c).First();
13: instructor.Courses.Add(course);
14: try
15: {
16: context.SaveChanges();
17: PopulateDropDownLists();
18: CourseAssignedLabel.Text = "Assignment successful.";
19: }
20: catch (Exception)
21: {
22: CourseAssignedLabel.Text = "Assignment unsuccessful.";
23: //Add code to log the error.
24: }
25: CourseAssignedLabel.Visible = true;
26: }
27: }
This code gets the Person
entity for the selected instructor, gets the Course
entity for the selected course, and adds the selected course to the Courses
navigation property of the instructor’s Person
entity. It then saves the changes to the database and repopulates the drop-down lists so the results can be seen immediately.
Add a handler for the Remove
button’s Click
event:
[!code-csharpMain]
1: protected void RemoveCourseButton_Click(object sender, EventArgs e)
2: {
3: using (var context = new SchoolEntities())
4: {
5: var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
6: var instructor = (from p in context.People
7: where p.PersonID == instructorID
8: select p).First();
9: var courseID = Convert.ToInt32(AssignedCoursesDropDownList.SelectedValue);
10: var courses = instructor.Courses;
11: var courseToRemove = new Course();
12: foreach (Course c in courses)
13: {
14: if (c.CourseID == courseID)
15: {
16: courseToRemove = c;
17: break;
18: }
19: }
20: try
21: {
22: courses.Remove(courseToRemove);
23: context.SaveChanges();
24: PopulateDropDownLists();
25: CourseRemovedLabel.Text = "Removal successful.";
26: }
27: catch (Exception)
28: {
29: CourseRemovedLabel.Text = "Removal unsuccessful.";
30: //Add code to log the error.
31: }
32: CourseRemovedLabel.Visible = true;
33: }
34: }
This code gets the Person
entity for the selected instructor, gets the Course
entity for the selected course, and removes the selected course from the Person
entity’s Courses
navigation property. It then saves the changes to the database and repopulates the drop-down lists so the results can be seen immediately.
Add code to the Page_Load
method that makes sure the error messages are not visible when there’s no error to report, and add handlers for the DataBound
and SelectedIndexChanged
events of the instructors drop-down list to populate the courses drop-down lists:
[!code-csharpMain]
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: CourseAssignedLabel.Visible = false;
4: CourseRemovedLabel.Visible = false;
5: }
6:
7: protected void InstructorsDropDownList_DataBound(object sender, EventArgs e)
8: {
9: PopulateDropDownLists();
10: }
11:
12: protected void InstructorsDropDownList_SelectedIndexChanged(object sender, EventArgs e)
13: {
14: PopulateDropDownLists();
15: }
Run the page.
Select an instructor. The Assign a Course drop-down list displays the courses that the instructor doesn’t teach, and the Remove a Course drop-down list displays the courses that the instructor is already assigned to. In the Assign a Course section, select a course and then click Assign. The course moves to the Remove a Course drop-down list. Select a course in the Remove a Course section and click Remove. The course moves to the Assign a Course drop-down list.
You have now seen some more ways to work with related data. In the following tutorial, you’ll learn how to use inheritance in the data model to improve the maintainability of your application.
|