[翻译][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);
}
修改Views\Course\Create.cshtml和Views\Course\Edit.cshtml的Departmetn显示名:
<label class="control-label col-md-2" for="DepartmentID">Department</label>
正常情况下,脚手架不会显示主键,因为主键的值由数据库产生并且不可改变并且它的显示对用户无意义。但是在Course实体的Create页面会有CourseID的编辑框,因为我们之前设置了DatabaseGeneratedOption.None属性。但是在其他页面不会自动产生,需要我们手动添加。
在Views\Course\Edit.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>
修改Views\Course\Delete.cshtml和Views\Course\Details.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>
运行程序:


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);
}
修改Views\Instructor\Edit.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>
运行:

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);
}
}
}
}
修改Views\Instructor\Edit.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>行必须在同一行,否则会报运行错误。
修改Views\Instructor\Index.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>
运行:


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;
}
}
修改Views\Instructor\Create.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 = ;
List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses; foreach (var course in courses)
{
if (cnt++ % == )
{
@:</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页面一样调整代码。
运行:

6.事务:
我们在之前的教程中提到过,EF隐式实现了事务。如果我们需要更多的控制,例如如果我们想要把在EF之外完成的操作包含在事务中,请参考:Working with Transactions。
[翻译][MVC 5 + EF 6] 8:更新相关数据的更多相关文章
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序更新相关数据
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第八篇:为ASP.NET MVC应用程序 ...
- ASP.NET MVC应用程序更新相关数据
为ASP.NET MVC应用程序更新相关数据 这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译, ...
- [翻译][MVC 5 + EF 6] 7:加载相关数据
原文:Reading Related Data with the Entity Framework in an ASP.NET MVC Application 1.延迟(Lazy)加载.预先(Eage ...
- [翻译][MVC 5 + EF 6] 2:基础的增删改查(CRUD)
原文:Implementing Basic CRUD Functionality with the Entity Framework in ASP.NET MVC Application 1.修改Vi ...
- [翻译][MVC 5 + EF 6] 6:创建更复杂的数据模型
原文:Creating a More Complex Data Model for an ASP.NET MVC Application 前面的教程中,我们使用的是由三个实体组成的简单的数据模型.在本 ...
- [翻译][MVC 5 + EF 6] 12[完结]:高级场景
原文:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application 1.执行原生SQL查询: EF Code First API ...
- [翻译][MVC 5 + EF 6] 11:实现继承
原文:Implementing Inheritance with the Entity Framework 6 in an ASP.NET MVC 5 Application 1.选择继承映射到数据库 ...
- [翻译][MVC 5 + EF 6] 10:处理并发
原文:Handling Concurrency with the Entity Framework 6 in an ASP.NET MVC 5 Application 1.并发冲突: 当一个用户编辑一 ...
- [翻译][MVC 5 + EF 6] 9:异步和存储过程
原文:Async and Stored Procedures with the Entity Framework in an ASP.NET MVC Application 1.为什么使用异步代码: ...
随机推荐
- mysql之存储引擎
1.存储引擎概念 打比方说:一部电影有mp4,wmv,avi,flv...等格式.同样的一部电影在硬盘上有不同的存储格式,所占的空间与清晰程度也各不一样. 那么我们表里的数据存储在硬盘上,是如何存储的 ...
- Java 判断是否为汉字 判断是否为乱码 判断字符串是否为双整型数字 整数 数字
/** * 判断是否为汉字 * * @param str * @return */ public static boolean isGBK(String str) { char[] ch ...
- 获取WMI硬件清单
WMI服务能够报告详细的硬件信息.通常,每个硬件都来自它们自己的WMI代理类.但是要找出这些硬件类的名字是不容易. 所有硬件类都在同一个WMI根下面,你可以在根类查询所有的硬件: Get-WmiObj ...
- Linux下查看CPU型号,内存大小,硬盘空间命令
1 查看CPU 1.1 查看CPU个数 # cat /proc/cpuinfo | grep "physical id" | uniq | wc -l 2 **uniq命令:删除重 ...
- 【转】C++对象内存分配问题
原文:http://blog.csdn.net/c504665913/article/details/7797859 如果一个人自称为程序高手,却对内存一无所知,那么我可以告诉你,他一定在吹牛.用C或 ...
- WM_VSCROLL
关键点 控制滚动条在最下面 实现过程 SendMessage(form1.Memo1.Handle,WM_VSCROLL,SB_BOTTOM,0); 图 备注 相关链接 来自为知笔记(Wiz)
- iOS开发——数据持久化Swift篇&模型对象归档
模型对象归档 import UIKit class ViewController: UIViewController { @IBOutlet weak var textField: UITextFie ...
- Jordan Lecture Note-6: The Solutions of Nonlinear Equation.
The Solutions of Nonlinear Equation 本文主要介绍几种用于解非线性方程$f(x)=0$的一些方法. (1) Bisection Method. 算法: step 1: ...
- Servlet, Listener 、 Filter.
Java Web的三大组件:Servlet, Listener . Filter. 使用Listener监听器:八大监听器: 第一组:用于监听Servlet三个域对象的创建与销毁 1. Servlet ...
- Spring3之JDBC
Spring提供了统一的数据访问异常层次体系,所涉及到的大部分异常类型都定义在org.springframework.dao包中,出于这个体系中所有异常类型均以org.springframework. ...