我在ASP.NET MVC Controller类中有一个Action方法,它处理来自相当基本的"创建/编辑用户"页面的表单帖子.我是MVC的新手,所以我一直在关注各种Microsoft教程的代码示例,这是该方法目前的样子:
[AcceptVerbs(HttpVerbs.Post)] public ViewResult Save([Bind(Prefix = "ServiceUser")]ServiceUser SUser) { if (SUser.ServiceUserId == 0) //new service user ServiceUserHelper.AddServiceUser(SUser); else //update to existing service user { using (ProjectDataContext db = DatabaseHelper.CreateContext()) { this.UpdateModel(db.ServiceUsers.Single(su => su.ServiceUserId == SUser.ServiceUserId), "ServiceUser"); db.SubmitChanges(); } } //return a confirmation view }
这很好用; 但是我的直觉告诉我'ProjectDataContext ...'代码不属于控制器.如果我要将Update功能移动到另一个类(以我使用Insert方法完成的方式),我将失去Controller的UpdateModel()方法的便利性,并且可能最终必须做一些非常详细的事情读取现有实体,更新其属性并提交更改.
所以我的问题是,实现这一目标的最佳方法是什么?LINQ中是否有类似于UpdateModel()的方法可以在提交之前将两个相同类型的实体合并在一起?
谢谢.
大多数人会建议使用"存储库模式"将数据访问代码移出控制器(并使用模拟对象而不是真实数据库进行单元测试).
以下是一些阅读更多的地方:
使用Linq到Sql和C#的存储库模式的实现示例
专业ASP.NET MVC的第1章(页32)
编辑:
我强烈建议阅读上面链接的整个Scott Guthrie章节.它有很多好的建议.也就是说,这里有一些相关的例子(本章除外)......
首先,我通常喜欢对"更新"与"添加"进行不同的操作.即使它们是用于呈现表单的相同View,通常也可以使用不同的URL来发布编辑和POST新记录.因此,以下是控制器更新操作中使用的存储库模式:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(int id, FormCollection formValues) { //get the current object from the database using the repository class Dinner dinner = dinnerRepository.GetDinner(id); try { //update the object with the values submitted UpdateModel(dinner); //save the changes dinnerRepository.Save(); //redirect the user back to the read-only action for what they just edited return RedirectToAction("Details", new { id = dinner.DinnerID }); } catch { //exception occurred, probably from UpdateModel, so handle the validation errors // (read the full chapter to learn what this extention method is) ModelState.AddRuleViolations(dinner.GetRuleViolations()); //render a view that re-shows the form with the validation rules shown return View(dinner); } }
这是"添加"示例:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Create() { //create a new empty object Dinner dinner = new Dinner(); try { //populate it with the values submitted UpdateModel(dinner); //add it to the database dinnerRepository.Add(dinner); //save the changes dinnerRepository.Save(); //redirect the user back to the read-only action for what they just added return RedirectToAction("Details", new { id = dinner.DinnerID }); } catch { //exception occurred, probably from UpdateModel, so handle the validation errors // (read the full chapter to learn what this extention method is) ModelState.AddRuleViolations(dinner.GetRuleViolations()); //render a view that re-shows the form with the validation rules shown return View(dinner); } }
对于上面的两个示例,DinnerRepository如下所示:
public class DinnerRepository { private NerdDinnerDataContext db = new NerdDinnerDataContext(); // // Query Methods public IQueryableFindAllDinners() { return db.Dinners; } public IQueryable FindUpcomingDinners() { return from dinner in db.Dinners where dinner.EventDate > DateTime.Now orderby dinner.EventDate select dinner; } public Dinner GetDinner(int id) { return db.Dinners.SingleOrDefault(d => d.DinnerID == id); } // // Insert/Delete Methods public void Add(Dinner dinner) { db.Dinners.InsertOnSubmit(dinner); } public void Delete(Dinner dinner) { db.RSVPs.DeleteAllOnSubmit(dinner.RSVPs); db.Dinners.DeleteOnSubmit(dinner); } // // Persistence public void Save() { db.SubmitChanges(); } }