.net 从MVC控制器类中删除数据库调用的最佳实践
我在ASP.NET MVC控制器类中有一个操作方法,该方法处理相当基本的“创建/编辑用户”页面中的表单帖子。我是MVC新手,所以我一直在遵循各种Microsoft教程中的代码示例,这是该方法当前的外观:.net 从MVC控制器类中删除数据库调用的最佳实践,.net,asp.net,asp.net-mvc,linq-to-sql,.net,Asp.net,Asp.net Mvc,Linq To Sql,我在ASP.NET MVC控制器类中有一个操作方法,该方法处理相当基本的“创建/编辑用户”页面中的表单帖子。我是MVC新手,所以我一直在遵循各种Microsoft教程中的代码示例,这是该方法当前的外观: [AcceptVerbs(HttpVerbs.Post)] public ViewResult Save([Bind(Prefix = "ServiceUser")]ServiceUser SUser) { if (SUser.ServiceUserId == 0) //new
[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…”代码不属于控制器。如果我将更新功能移动到另一个类(就像我使用Insert方法所做的那样),我将失去控制器的UpdateModel()方法的便利性,并且可能最终不得不做一些非常详细的事情来读取现有实体、更新其属性并提交更改
所以我的问题是,实现这一目标的最佳方式是什么?LINQ中是否有类似于UpdateModel()的方法,可以在提交之前将相同类型的两个实体合并在一起
谢谢。大多数人会建议使用“存储库模式”将数据访问代码移出控制器(并启用模拟对象而不是真实数据库的单元测试) 以下是一些可以阅读更多内容的地方:
- (第32页)
[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);
}
}
以下是“添加”示例:
对于上述两个示例,DinnerRepository如下所示:
public class DinnerRepository
{
private NerdDinnerDataContext db = new NerdDinnerDataContext();
//
// Query Methods
public IQueryable<Dinner> FindAllDinners()
{
return db.Dinners;
}
public IQueryable<Dinner> 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();
}
}
公共类晚餐地址
{
private NerdDinnerDataContext db=new NerdDinnerDataContext();
//
//查询方法
公共可查询的FindAllDinners()
{
返回db.晚餐;
}
公共可查询的FindUpcomingDinners()
{
晚餐后返回db。晚餐
where deline.EventDate>DateTime.Now
按晚餐点菜。EventDate
选择晚餐;
}
公共晚餐(int id)
{
返回db.Dinners.SingleOrDefault(d=>d.DinnerID==id);
}
//
//插入/删除方法
公共空间添加(晚餐)
{
db.晚餐。InsertOnSubmit(晚餐);
}
公共空间删除(晚餐)
{
db.RSVPs.DeleteAllOnSubmit(晚餐.RSVPs);
db.dinters.deleteosubmit(晚餐);
}
//
//坚持
公共作废保存()
{
db.SubmitChanges();
}
}
大多数人会建议使用“存储库模式”将数据访问代码移出控制器(并启用模拟对象而不是真实数据库的单元测试)
以下是一些可以阅读更多内容的地方:
- (第32页)
[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);
}
}
以下是“添加”示例:
对于上述两个示例,DinnerRepository如下所示:
public class DinnerRepository
{
private NerdDinnerDataContext db = new NerdDinnerDataContext();
//
// Query Methods
public IQueryable<Dinner> FindAllDinners()
{
return db.Dinners;
}
public IQueryable<Dinner> 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();
}
}
公共类晚餐地址
{
private NerdDinnerDataContext db=new NerdDinnerDataContext();
//
//查询方法
公共可查询的FindAllDinners()
{
返回db.晚餐;
}
公共可查询的FindUpcomingDinners()
{
晚餐后返回db。晚餐
where deline.EventDate>DateTime.Now
按晚餐点菜。EventDate
选择晚餐;
}
公共晚餐(int id)
{
返回db.Dinners.SingleOrDefault(d=>d.DinnerID==id);
}
//
//插入/删除方法
公共空间添加(晚餐)
{
db.晚餐。InsertOnSubmit(晚餐);
}
公共空间删除(晚餐)
{
db.RSVPs.DeleteAllOnSubmit(晚餐.RSVPs);
db.dinters.deleteosubmit(晚餐);
}
//
//坚持
公共作废保存()
{
db.SubmitChanges();
}
}
我同意李的观点,我也一直在找东西。我在MVC预览的早期对反射做了类似的事情,该预览用于模型而不是控制器。这不是最好的代码,并且认为MVC最终版会添加一些东西。没有什么东西卡在控制器里。如果使用强类型视图,最好将表单或模型通过控制器传递到模型中,并让所有验证和数据移动都在那里完成。现在,即使是一个做得很差的控制器也无法传输数据。我同意李的观点,我也一直在寻找一些东西。我在MVC预览的早期对反射做了类似的事情,该预览用于模型而不是控制器。这不是最好的代码,并且认为MVC最终版会添加一些东西。没有什么东西卡在控制器里。如果使用强类型视图,最好将表单或模型通过控制器传递到模型中,并让所有验证和数据移动都在那里完成。现在,即使是一个做得很差的控制器也无法输送数据。您目前拥有一个我称之为2层的体系结构,其中包括MVC应用层(ie控制器)和数据访问层
您可能希望通过在控制器和DAL之间插入服务层,从而移动到3层或4层体系结构。那么你呢
public class UserService : IUserService
{
public void Save(ServiceUser SUser)
{
// insert or update user info
if (SUser.ServiceUserId == 0) //new service user
ServiceUserHelper.AddServiceUser(SUser);
else //update to existing service user
{
using (ProjectDataContext db = DatabaseHelper.CreateContext())
{
db.ServiceUsers.Single(su => su.ServiceUserId ==
SUser.ServiceUserId);
db.SubmitChanges();
}
}
}
}