Khoanglang89
Bạn hãy đăng nhập hoặc đăng ký
Khoanglang89
Bạn hãy đăng nhập hoặc đăng ký
Khoanglang89

NHẬN THIẾT KẾ WEBSITE/ SOFTWARE - LÀM ĐỒ ÁN TỐT NGHIỆP, ĐỒ ÁN CHUYÊN MÔN NGÀNH CÔNG NGHỆ THÔNG TIN


You are not connected. Please login or register

Xem chủ đề cũ hơn Xem chủ đề mới hơn Go down  Thông điệp [Trang 1 trong tổng số 1 trang]

Admin

Admin

Admin
Admin
Loading
In the previous tutorial you displayed related data; in this tutorial you'll update related data. For most relationships, this can be done by updating either foreign key fields or navigation properties. For many-to-many relationships, the Entity Framework doesn't expose the join table directly, so you add and remove entities to and from the appropriate navigation properties.

The following illustrations show some of the pages that you'll work with.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application CreateCourse

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application CoursesEdit

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorEditWithCourses

Customize the Create and Edit Pages for Courses


When a new course entity is created, it must have a relationship to an existing department. To facilitate this, the scaffolded code includes controller methods and Create and Edit views that include a drop-down list for selecting the department. The drop-down list sets the
Code:
Course.DepartmentID
foreign key property, and that's all the Entity Framework needs in order to load the
Code:
Department
navigation property with the appropriate
Code:
Department
entity. You'll use the scaffolded code, but change it slightly to add error handling and sort the drop-down list.

In CourseController.cs, delete the four
Code:
Create
and
Code:
Edit
methods and replace them with the following code:

public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CourseID,Title,Credits,DepartmentID")]Course course)
{
try
{
if (ModelState.IsValid)
{
db.Courses.Add(course);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}

public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Course course = db.Courses.Find(id);
if (course == null)
{
return HttpNotFound();
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var courseToUpdate = db.Courses.Find(id);
if (TryUpdateModel(courseToUpdate, "",
new string[] { "Title", "Credits", "DepartmentID" }))
{
try
{
db.SaveChanges();

return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
PopulateDepartmentsDropDownList(courseToUpdate.DepartmentID);
return View(courseToUpdate);
}

private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
{
var departmentsQuery = from d in db.Departments
orderby d.Name
select d;
ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);
}

Add the following
Code:
using
statement at the beginning of the file:

using System.Data.Entity.Infrastructure;

The
Code:
PopulateDepartmentsDropDownList
method gets a list of all departments sorted by name, creates a
Code:
SelectList
collection for a drop-down list, and passes the collection to the view in a
Code:
ViewBag
property. The method accepts the optional
Code:
selectedDepartment
parameter that allows the calling code to specify the item that will be selected when the drop-down list is rendered. The view will pass the name
Code:
DepartmentID
to the DropDownList helper, and the helper then knows to look in the
Code:
ViewBag
object for a
Code:
SelectList
named
Code:
DepartmentID
.

The
Code:
HttpGet

Code:
Create
method calls the
Code:
PopulateDepartmentsDropDownList
method without setting the selected item, because for a new course the department is not established yet:

public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}

The
Code:
HttpGet

Code:
Edit
method sets the selected item, based on the ID of the department that is already assigned to the course being edited:

public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Course course = db.Courses.Find(id);
if (course == null)
{
return HttpNotFound();
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}

The
Code:
HttpPost
methods for both
Code:
Create
and
Code:
Edit
also include code that sets the selected item when they redisplay the page after an error:

catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);

This code ensures that when the page is redisplayed to show the error message, whatever department was selected stays selected.

The Course views are already scaffolded with drop-down lists for the department field, but you don't want the DepartmentID caption for this field, so make the following highlighted change to the Views\Course\Create.cshtml file to change the caption.

@model ContosoUniversity.Models.Course

@{
ViewBag.Title = "Create";
}

Create




@using (Html.BeginForm())
{
@Html.AntiForgeryToken()


Course




@Html.ValidationSummary(true)


@Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.CourseID)
@Html.ValidationMessageFor(model => model.CourseID)




@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)




@Html.LabelFor(model => model.Credits, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.Credits)
@Html.ValidationMessageFor(model => model.Credits)






@Html.DropDownList("DepartmentID", String.Empty)
@Html.ValidationMessageFor(model => model.DepartmentID)









}


@Html.ActionLink("Back to List", "Index")


@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

Make the same change in Views\Course\Edit.cshtml.

Normally the scaffolder doesn't scaffold a primary key because the key value is generated by the database and can't be changed and isn't a meaningful value to be displayed to users. For Course entities the scaffolder does include an text box for the
Code:
CourseID
field because it understands that the
Code:

DatabaseGeneratedOption.None
attribute means the user should be able enter the primary key value. But it doesn't understand that because the number is meaningful you want to see it in the other views, so you need to add it manually.

In Views\Course\Edit.cshtml, add a course number field before the Title field. Because it's the primary key, it's displayed, but it can't be changed.


@Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" })

@Html.DisplayFor(model => model.CourseID)



There's already a hidden field (
Code:
Html.HiddenFor
helper) for the course number in the Edit view. Adding an Html.LabelFor helper doesn't eliminate the need for the hidden field because it doesn't cause the course number to be included in the posted data when the user clicks Save on the Edit page.

In Views\Course\Delete.cshtml and Views\Course\Details.cshtml, change the department name caption from "Name" to "Department" and add a course number field before the Title field.


Department



@Html.DisplayFor(model => model.Department.Name)



@Html.DisplayNameFor(model => model.CourseID)



@Html.DisplayFor(model => model.CourseID)


Run the Create page (display the Course Index page and click Create New) and enter data for a new course:

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application CreateCourse

Click Create. The Course Index page is displayed with the new course added to the list. The department name in the Index page list comes from the navigation property, showing that the relationship was established correctly.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application NewCourseInIndex

Run the Edit page (display the Course Index page and click Edit on a course).

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application CoursesEdit

Change data on the page and click Save. The Course Index page is displayed with the updated course data.

Adding an Edit Page for Instructors


When you edit an instructor record, you want to be able to update the instructor's office assignment. The
Code:
Instructor
entity has a one-to-zero-or-one relationship with the
Code:
OfficeAssignment
entity, which means you must handle the following situations:


  • If the user clears the office assignment and it originally had a value, you must remove and delete the
    Code:
    OfficeAssignment
    entity.
  • If the user enters an office assignment value and it originally was empty, you must create a new
    Code:
    OfficeAssignment
    entity.
  • If the user changes the value of an office assignment, you must change the value in an existing
    Code:
    OfficeAssignment
    entity.


Open InstructorController.cs and look at the
Code:
HttpGet

Code:
Edit
method:

{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Instructor instructor = db.Instructors.Find(id);
if (instructor == null)
{
return HttpNotFound();
}
ViewBag.ID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.ID);
return View(instructor);
}

The scaffolded code here isn't what you want. It's setting up data for a drop-down list, but you what you need is a text box. Replace this method with the following code:

public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.ID == id)
.Single();
if (instructor == null)
{
return HttpNotFound();
}
return View(instructor);
}

This code drops the
Code:
ViewBag
statement and adds eager loading for the associated
Code:
OfficeAssignment
entity. You can't perform eager loading with the
Code:
Find
method, so the
Code:
Where
and
Code:
Single
methods are used instead to select the instructor.

Replace the
Code:
HttpPost

Code:
Edit
method with the following code. which handles office assignment updates:

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.ID == id)
.Single();

if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}

db.SaveChanges();

return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
return View(instructorToUpdate);
}

The reference to
Code:
RetryLimitExceededException
requires a
Code:

using
statement; to add it, right-click
Code:
RetryLimitExceededException
, and then click Resolve - using System.Data.Entity.Infrastructure.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application Resolve

The code does the following:


  • Changes the method name to
    Code:
    EditPost
    because the signature is now the same as the
    Code:
    HttpGet
    method (the
    Code:
    ActionName
    attribute specifies that the /Edit/ URL is still used).
  • Gets the current
    Code:
    Instructor
    entity from the database using eager loading for the
    Code:
    OfficeAssignment
    navigation property. This is the same as what you did in the
    Code:
    HttpGet

    Code:
    Edit
    method.
  • Updates the retrieved
    Code:
    Instructor
    entity with values from the model binder. The TryUpdateModel overload used enables you to whitelist the properties you want to include. This prevents over-posting, as explained in the second tutorial.
    if (TryUpdateModel(instructorToUpdate, "",
    new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
  • If the office location is blank, sets the
    Code:
    Instructor.OfficeAssignment
    property to null so that the related row in the
    Code:
    OfficeAssignment
    table will be deleted.
    if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
    {
    instructorToUpdate.OfficeAssignment = null;
    }
  • Saves the changes to the database.


In Views\Instructor\Edit.cshtml, after the
Code:
div
elements for the Hire Date field, add a new field for editing the office location:


@Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)



Run the page (select the Instructors tab and then click Edit on an instructor). Change the Office Location and click Save.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorEdit

Adding Course Assignments to the Instructor Edit Page


Instructors may teach any number of courses. Now you'll enhance the Instructor Edit page by adding the ability to change course assignments using a group of check boxes, as shown in the following screen shot:

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorEditWithCourses

The relationship between the
Code:
Course
and
Code:
Instructor
entities is many-to-many, which means you do not have direct access to the foreign key properties which are in the join table. Instead, you add and remove entities to and from the
Code:
Instructor.Courses
navigation property.

The UI that enables you to change which courses an instructor is assigned to is a group of check boxes. A check box for every course in the database is displayed, and the ones that the instructor is currently assigned to are selected. The user can select or clear check boxes to change course assignments. If the number of courses were much greater, you would probably want to use a different method of presenting the data in the view, but you'd use the same method of manipulating navigation properties in order to create or delete relationships.

To provide data to the view for the list of check boxes, you'll use a view model class. Create AssignedCourseData.cs in the ViewModels folder and replace the existing code with the following code:

namespace ContosoUniversity.ViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}

In InstructorController.cs, replace the
Code:
HttpGet

Code:
Edit
method with the following code. The changes are highlighted.

public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.ID == id)
.Single();
PopulateAssignedCourseData(instructor);
if (instructor == null)
{
return HttpNotFound();
}
return View(instructor);
}

private void PopulateAssignedCourseData(Instructor instructor)
{
var allCourses = db.Courses;
var instructorCourses = new HashSet(instructor.Courses.Select(c => c.CourseID));
var viewModel = new List();
foreach (var course in allCourses)
{
viewModel.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
ViewBag.Courses = viewModel;
}

The code adds eager loading for the
Code:
Courses
navigation property and calls the new
Code:
PopulateAssignedCourseData
method to provide information for the check box array using the
Code:
AssignedCourseData
view model class.

The code in the
Code:
PopulateAssignedCourseData
method reads through all
Code:
Course
entities in order to load a list of courses using the view model class. For each course, the code checks whether the course exists in the instructor's
Code:
Courses
navigation property. To create efficient lookup when checking whether a course is assigned to the instructor, the courses assigned to the instructor are put into a HashSet collection. The
Code:
Assigned
property  is set to
Code:
true
  for courses the instructor is assigned. The view will use this property to determine which check boxes must be displayed as selected. Finally, the list is passed to the view in a
Code:
ViewBag
property.

Next, add the code that's executed when the user clicks Save. Replace the
Code:
EditPost
method with the following code, which calls a new method that updates the
Code:
Courses
navigation property of the
Code:
Instructor
entity. The changes are highlighted.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int? id, string[] selectedCourses)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.ID == id)
.Single();

if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}

UpdateInstructorCourses(selectedCourses, instructorToUpdate);

db.SaveChanges();

return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List();
return;
}
 
var selectedCoursesHS = new HashSet(selectedCourses);
var instructorCourses = new HashSet
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
}

The method signature is now different from the
Code:
HttpGet

Code:

Edit
method, so the method name changes from
Code:
EditPost
back to
Code:
Edit
.

Since the view doesn't have a collection of
Code:
Course
entities, the model binder can't automatically update the
Code:
Courses
navigation property. Instead of using the model binder to update the
Code:
Courses
navigation property, you'll do that in the new
Code:
UpdateInstructorCourses
method. Therefore you need to exclude the
Code:
Courses
property from model binding. This doesn't require any change to the code that calls TryUpdateModel because you're using the whitelisting overload and
Code:
Courses
isn't in the include list.

If no check boxes were selected, the code in
Code:
UpdateInstructorCourses
initializes the
Code:
Courses
navigation property with an empty collection:

if (selectedCourses == null)
{
instructorToUpdate.Courses = new List();
return;
}

The code then loops through all courses in the database and checks each course against the ones currently assigned to the instructor versus the ones that were selected in the view. To facilitate efficient lookups, the latter two collections are stored in
Code:
HashSet
objects.

If the check box for a course was selected but the course isn't in the
Code:
Instructor.Courses
navigation property, the course is added to the collection in the navigation property.

if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}

If the check box for a course wasn't selected, but the course is in the
Code:
Instructor.Courses
navigation property, the course is removed from the navigation property.

else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}

In Views\Instructor\Edit.cshtml, add a Courses field with an array of check boxes by adding the following code immediately after the
Code:
div
elements for the
Code:
OfficeAssignment
field and before the
Code:
div
element for the Save button:





@{
int cnt = 0;
List courses = ViewBag.Courses;

foreach (var course in courses)
{
if (cnt++ % 3 == 0)
{
@:

}
@:
}
@:
}

name="selectedCourses"
value="@course.CourseID"
@(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
@course.CourseID @: @course.Title
@:



After you paste the code, if line breaks and indentation don't look like they do here, manually fix everything so that it looks like what you see here. The indentation doesn't have to be perfect, but the
Code:
@</tr><tr>
,
Code:
@:<td>
,
Code:
@:</td>
, and
Code:
@</tr>
lines must each be on a single line as shown or you'll get a runtime error.

This code creates an HTML table that has three columns. In each column is a check box followed by a caption that consists of the course number and title. The check boxes all have the same name ("selectedCourses"), which informs the model binder that they are to be treated as a group. The
Code:
value
attribute of each check box is set to the value of
Code:
CourseID.
When the page is posted, the model binder passes an array to the controller that consists of the
Code:
CourseID
values for only the check boxes which are selected.

When the check boxes are initially rendered, those that are for courses assigned to the instructor have
Code:
checked
attributes, which selects them (displays them checked).

After changing course assignments, you'll want to be able to verify the changes when the site returns to the
Code:
Index
page. Therefore, you need to add a column to the table in that page. In this case you don't need to use the
Code:
ViewBag
object, because the information you want to display is already in the
Code:
Courses
navigation property of the
Code:
Instructor
entity that you're passing to the page as the model.

In Views\Instructor\Index.cshtml, add a Courses heading immediately following the Office heading, as shown in the following example:


Last Name
First Name
Hire Date
Office
Courses



Then add a new detail cell immediately following the office location detail cell:


@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}


@{
foreach (var course in item.Courses)
{
@course.CourseID @: @course.Title

}
}


@Html.ActionLink("Select", "Index", new { id = item.ID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })


Run the Instructor Index page to see the courses assigned to each instructor:

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorsWithCourses

Click Edit on an instructor to see the Edit page.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorEditWithCourses

Change some course assignments and click Save. The changes you make are reflected on the Index page.
Note: The approach taken here to edit instructor course data works well when there is a limited number of courses. For collections that are much larger, a different UI and a different updating method would be required.
 

Update the DeleteConfirmed Method


In InstructorController.cs, delete the
Code:

DeleteConfirmed
method and insert the following code in its place.

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.ID == id)
.Single();

db.Instructors.Remove(instructor);

var department = db.Departments
.Where(d => d.InstructorID == id)
.SingleOrDefault();
if (department != null)
{
department.InstructorID = null;
}

db.SaveChanges();
return RedirectToAction("Index");
}

This code makes the following change:


  • If the instructor is assigned as administrator of any department, removes the instructor assignment from that department. Without this code, you would get a referential integrity error if you tried to delete an instructor who was assigned as administrator for a department.


This code doesn't handle the scenario of one instructor assigned as administrator for multiple departments. In the last tutorial you'll add code that prevents that scenario from happening.

Add office location and courses to the Create page


In InstructorController.cs, delete the
Code:
HttpGet
and
Code:
HttpPost

Code:
Create
methods, and then add the following code in their place:

public ActionResult Create()
{
var instructor = new Instructor();
instructor.Courses = new List();
PopulateAssignedCourseData(instructor);
return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "LastName,FirstMidName,HireDate,OfficeAssignment" )]Instructor instructor, string[] selectedCourses)
{
if (selectedCourses != null)
{
instructor.Courses = new List();
foreach (var course in selectedCourses)
{
var courseToAdd = db.Courses.Find(int.Parse(course));
instructor.Courses.Add(courseToAdd);
}
}
if (ModelState.IsValid)
{
db.Instructors.Add(instructor);
db.SaveChanges();
return RedirectToAction("Index");
}
PopulateAssignedCourseData(instructor);
return View(instructor);
}

This code is similar to what you saw for the Edit methods except that initially no courses are selected. The
Code:
HttpGet

Code:
Create
method calls the
Code:
PopulateAssignedCourseData
method not because there might be courses selected but in order to provide an empty collection for the
Code:
foreach
loop in the view (otherwise the view code would throw a null reference exception).

The HttpPost Create method adds each selected course to the Courses navigation property before the template code that checks for validation errors and adds the new instructor to the database. Courses are added even if there are model errors so that when there are model errors (for an example, the user keyed an invalid date) so that when the page is redisplayed with an error message, any course selections that were made are automatically restored.

Notice that in order to be able to add courses to the
Code:
Courses
navigation property you have to initialize the property as an empty collection:

instructor.Courses = new List();

As an alternative to doing this in controller code, you could do it in the Instructor model by changing the property getter to automatically create the collection if it doesn't exist, as shown in the following example:

private ICollection _courses;
public virtual ICollection Courses
{
get
{
return _courses ?? (_courses = new List());
}
set
{
_courses = value;
}
}

If you modify the
Code:
Courses
property in this way, you can remove the explicit property initialization code in the controller.

In Views\Instructor\Create.cshtml, add an office location text box and course check boxes after the hire date field and before the Submit button.


@Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)







@{
int cnt = 0;
List courses = ViewBag.Courses;

foreach (var course in courses)
{
if (cnt++ % 3 == 0)
{
@:

}
@:
}
@:
}

name="selectedCourses"
value="@course.CourseID"
@(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
@course.CourseID @: @course.Title
@:



After you paste the code, fix line breaks and indentation as you did earlier for the Edit page.

Run the Create page and add an instructor.

8_Updating Related Data with the Entity Framework in an ASP.NET MVC Application InstructorCreateWithCourses

Handling Transactions


As explained in the Basic CRUD Functionality tutorial, by default the Entity Framework implicitly implements transactions. For scenarios where you need more control -- for example, if you want to include operations done outside of Entity Framework in a transaction -- see Working with Transactions on MSDN.

Summary


You have now completed this introduction to working with related data. So far in these tutorials you've worked with code that does synchronous I/O. You can make the application use web server resources more efficiently by implementing asynchronous code, and that's what you'll do in the next tutorial.

Please leave feedback on how you liked this tutorial and what we could improve. You can also request new topics at Show Me How With Code.

Links to other Entity Framework resources can be found in ASP.NET Data Access - Recommended Resources.

https://khoanglang89.forumvi.com

Xem chủ đề cũ hơn Xem chủ đề mới hơn Về Đầu Trang  Thông điệp [Trang 1 trong tổng số 1 trang]

Bài viết mới cùng chuyên mục

      Permissions in this forum:
      Bạn không có quyền trả lời bài viết