关注点分离的 MVC 最佳实践

MVC best practice for seperation of concerns

我正在使用 MVC5 制作网站。

我正在使用脚手架从我的模型生成我的控制器-class。每当它创建控制器的脚手架时,数据库连接和模型操作都会在控制器内发生class(见下文)。通过查看此 thread,我可以看出大多数人都同意这应该发生在模型 class 中。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Username")] User user)
{
    if (ModelState.IsValid)
    {
        db.Entry(user).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
  return View(user);
}

与其让控制器执行此操作,不如让它看起来像这样?:

用户控制器

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Username")] User user)
{
    if (ModelState.IsValid)
    {
        UserModel userModel = new userModel();
        userModel.editUser(user);
        return RedirectToAction("Index");
    }
  return View(user);
}

用户模型

public void editUser(User user){
    db.Entry(user).State = EntityState.Modified;
    db.SaveChanges();
}

要指定 "db" 是什么,它将是对我的数据库上下文的引用。

我认为您误解了您引用的答案 (In a MVC application, should the controller or the model handle data access?) 中 "Model" 的含义。

tereško 的回答是:

The business logic in MVC and MVC-inspired patterns has to be in the model layer. And yes, model is supposed to be a layer, not a class or object.

所以不要将数据库访问权限放入您的 ViewModel。相反,您需要业务层中的服务 class 进行数据库访问并将数据库实体映射到数据传输对象或 ViewModel。请注意我如何使用 Command 和 Query classes 将对业务层的访问与任何前端 classes 分离,例如 ViewModels(使用 AutoMapper 在 DTO <-> ViewModel <-> Command/Query).

public interface IUserService {

    public UserDto CreateUser(CreateUserCommand command);

    public UserDto EditUser(EditUserCommand command);

    public void DeleteUser(DeleteUserCommand command);

    public UserDto[] FindUsers(FindUsersQuery query);
}

控制器使用此业务层:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserViewModel postData) {
     if (!ModelState.IsValid) {
         return View("Edit", postData);
     }

     var command = Mapper.Map<EditUserCommand>(postData);
     var updatedUserDto = _userService.EditUser(command);

     var updatedUserViewModel = Mapper.Map<UserViewModel>(updatedUserDto);
     return View("Show", updatedUserViewModel);
}