zoukankan      html  css  js  c++  java
  • [翻译][MVC 5 + EF 6] 8:更新相关数据

    原文:Updating Related Data with the Entity Framework in an ASP.NET MVC Application

    1.定制Course的Create和Edit页面

      修改CourseController.cs的Create和Edit方法:

    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);
    } 

      修改ViewsCourseCreate.cshtmlViewsCourseEdit.cshtml的Departmetn显示名:

    <label class="control-label col-md-2" for="DepartmentID">Department</label>

      正常情况下,脚手架不会显示主键,因为主键的值由数据库产生并且不可改变并且它的显示对用户无意义。但是在Course实体的Create页面会有CourseID的编辑框,因为我们之前设置了DatabaseGeneratedOption.None属性。但是在其他页面不会自动产生,需要我们手动添加。

      在ViewsCourseEdit.cshtml添加:

    <div class="form-group">
        @Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DisplayFor(model => model.CourseID)
        </div>
    </div>

      修改ViewsCourseDelete.cshtmlViewsCourseDetails.cshtml

    <dt>
        Department
    </dt>
    
    <dd>
        @Html.DisplayFor(model => model.Department.Name)
    </dd>
    
    <dt>
        @Html.DisplayNameFor(model => model.CourseID)
    </dt>
    
    <dd>
        @Html.DisplayFor(model => model.CourseID)
    </dd>

      运行程序:

    Course_create_page

    Course_edit_page

    2.给Instructor添加Edit页面

      修改Edit的GET方法:

    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);
    }

      修改过Edit的POST方法:

    [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);
    }

      修改ViewsInstructorEdit.cshtml,在Hire Date后添加:

    <div class="form-group">
        @Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.OfficeAssignment.Location)
            @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
        </div>
    </div>

      运行:

    Changing_the_office_location

    3.为Instructor的Edit页面添加分配Course

      在ViewModels文件夹新建AssignedCourseData.cs

        public class AssignedCourseData
        {
            public int CourseID { get; set; }
            public string Title { get; set; }
            public bool Assigned { get; set; }
        }

      修改InstructorController.cs中Edit的GET:

    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<int>(instructor.Courses.Select(c => c.CourseID));
        var viewModel = new List<AssignedCourseData>();
        foreach (var course in allCourses)
        {
            viewModel.Add(new AssignedCourseData
            {
                CourseID = course.CourseID,
                Title = course.Title,
                Assigned = instructorCourses.Contains(course.CourseID)
            });
        }
        ViewBag.Courses = viewModel;
    }

      修改InstructorController.cs中Edit的POST:

    [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<Course>();
          return;
       }
     
       var selectedCoursesHS = new HashSet<string>(selectedCourses);
       var instructorCourses = new HashSet<int>
           (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);
             }
          }
       }
    }

      修改ViewsInstructorEdit.cshtml,在Save按钮之前添加:

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <table>
                <tr>
                    @{
                        int cnt = 0;
                        List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;
    
                        foreach (var course in courses)
                        {
                            if (cnt++ % 3 == 0)
                            {
                                @:</tr><tr>
                            }
                            @:<td>
                                <input type="checkbox"
                                   name="selectedCourses"
                                   value="@course.CourseID"
                                   @(Html.Raw(course.Assigned ? "checked="checked"" : "")) />
                                   @course.CourseID @:  @course.Title
                            @:</td>
                        }
                        @:</tr>
                    }
            </table>
        </div>
    </div>

      上面的代码粘贴后,如果换行和缩进和上述代码不一样,需要手动修改。缩进可以不修改,但@</tr><tr>, @:<td>, @:</td>@</tr>行必须在同一行,否则会报运行错误。

      修改ViewsInstructorIndex.cshtml

    <tr> 
        <th>Last Name</th> 
        <th>First Name</th> 
        <th>Hire Date</th> 
        <th>Office</th>
        <th>Courses</th>
        <th></th> 
    </tr> 
    <td>
        @if (item.OfficeAssignment != null)
        {
            @item.OfficeAssignment.Location
        }
    </td>
    <td>
        @{
            foreach (var course in item.Courses)
            {
                @course.CourseID @:  @course.Title <br />
            }
        }
    </td>
    <td>
        @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 })
    </td>

      运行:

    Instructor_index_page

    Instructor_edit_page_with_courses

    4.修改InstructorController.cs的DeleteConfirmed方法

    [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");
    }

    5.给InstructorController.cs的Create页面添加office location和course

      修改Create方法:

    public ActionResult Create()
    {
        var instructor = new Instructor();
        instructor.Courses = new List<Course>();
        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<Course>();
            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);
    }

      注意,为了能够给Course导航属性添加course,必须初始化属性为空的集合:

    instructor.Courses = new List<Course>();

      为了达到这个目的,我们也可以这样写:

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

      修改ViewsInstructorCreate.cshtml,在Submit按钮之前添加:

    <div class="form-group">
        @Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.OfficeAssignment.Location)
            @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
        </div>
    </div>
    
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <table>
                <tr>
                    @{
                        int cnt = 0;
                        List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;
    
                        foreach (var course in courses)
                        {
                            if (cnt++ % 3 == 0)
                            {
                                @:</tr><tr>
                            }
                            @:<td>
                                <input type="checkbox"
                                   name="selectedCourses"
                                   value="@course.CourseID"
                                   @(Html.Raw(course.Assigned ? "checked="checked"" : "")) />
                                   @course.CourseID @:  @course.Title
                            @:</td>
                        }
                        @:</tr>
                    }
            </table>
        </div>
    </div>

      粘贴代码后,也要像Edit页面一样调整代码。

      运行:

    Instructor Create with Courses

    6.事务

      我们在之前的教程中提到过,EF隐式实现了事务。如果我们需要更多的控制,例如如果我们想要把在EF之外完成的操作包含在事务中,请参考:Working with Transactions

  • 相关阅读:
    (转)golang获取当前时间、时间戳和时间字符串及它们之间的相互转换
    FFmpeg常用命令
    go cmd nohup 的坑
    Nginx配置详解(转)
    记录一次go性能调试的过程
    github徽标引入
    golang 关于 interface 的学习整理
    <转>Go语言TCP Socket编程
    [转]Go里面的unsafe包详解
    linux extglob模式 和rm反选
  • 原文地址:https://www.cnblogs.com/walden1024/p/4599978.html
Copyright © 2011-2022 走看看