使用ViewModel是否有意义

时间:2011-07-13 07:29:22

标签: asp.net-mvc model-view-controller asp.net-mvc-3

我在MVC3编程中尝试自己。在查看示例应用程序的过程中,我经常会看到模型,视图和控制器之外的ViewModel等内容。

我的问题:使用它们是否有意义?如果是:如何和模型和ViewModel之间的差异?

非常感谢!

编辑: 谢谢你的回答:

这意味着如果我有一个模型用户:

public string Username {get;set;}
public string mail{get;set;}
public string password{get;set;}
public string gender {get;set;}

And some methods like:
public int instertUserToDb()
{
...
}
public bool UserAllreadyExists()
{
...
}
public bool UpdateUserDatas()
{
...
}

Viewmodel不包含与数据库的任何连接?我需要创建一个ViewModel:NewUser,UpdateUser,UserDetails?

将所有内容(如插入,选择等)放入模型并将ViewModel用作视图的模板是否正确?有没有人知道互联网上的好例子?

非常感谢!

8 个答案:

答案 0 :(得分:8)

不仅有意义,ViewModels是唯一应该在MVC中使用的。它们提供了许多好处,其中主要是静态类型和编译时间检查。 ViewData和ViewBag依赖于丑陋的字符串和动态属性名称,这些名称很难维护且容易出错。在asp.net MVC中,M代表ViewModel s,而不是域模型。模型是业务,域实体,它封装了业务逻辑,旨在在域内工作。尽管使用了演示技术,模型保持不变,无论是Windows应用程序,Silverlight,ASP.NET MVC还是其他。相比之下,asp.net MVC中的ViewModels是专为在MVC框架内工作而设计的类,它们特定于控制器并查看特定数据,并允许更轻松地在域模型和控制器之间进行迭代。例如,在域(模型)中设计用户实体时

public class User
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

为您的应用程序设计登录控制器时 - UserViewModel

public class UserViewModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
    public string LoginHelpText { get; set; }
}

这不是现实生活中的例子,但在设计视图模型和设计领域模型时,您应该看到主要区别。如您所见,ViewModel是模式控制器和特定于操作的,并且包含用于更好的表示和用户迭代的数据,而域模型被设计为在域内工作而不关心表示 - 域模型不需要第二个ConfirmPassword字段例如。为了更好地将ViewModel用于域模型,您可以查看AutoMapper和其他社区工具。

ViewModels不应包含数据库的数据访问逻辑,也不应包含业务逻辑。在这种情况下,Models也不应包含对数据库的访问权限。为此,您应该创建存储库。

public interface IUserRepository
{
    int Create(User user);
    bool UserAlreadyExists(string userName);
    bool UpdateUserDatas(User user);
}

//than the implementation

public class UserRepository
{
    // Implementation of user repository.
}

//controller

public class UserController
{
    IUserRepository _userRepository;
    public UserController(IUserRepository userRepository)
    {
        _userRepository = userRepository ?? new UserRepository();// better to write this using Dependency Injection. Search google for Ninject, StructureMap, Unity, etc
    }

    public ActionResult Create(UserViewModel user)
    {
        if (ModelState.IsValid)
        {
            User domainUser = new User()
            {
                UserName = user.UserName // etc. written for simplicity, Use Automapper instead
            };
            _userRepository.Create(domainUser);// create user via repository
            return RedirectToAction("Index");
        }
        return View(user);
    }
}

阅读steven sanderson的书籍pro asp.net mvc 3了解详情

答案 1 :(得分:2)

模型是域对象。最佳实践是使用视图模型而不是域对象,因为有时表示逻辑与域模型不同。看到这个 When do I use View Models, Partials, Templates and handle child bindings with MVC 3

答案 2 :(得分:2)

让我们举一个关于博客应用的例子。这是您的博客模型;

  public class Blog {

    public int BlogID {get;set;}
    public string Title {get;set;}
    public DateTime PublishDate {get;set;}
    public string Content {get;set;}

  }

这是你的评论模型;

  public class Comment {

    public int CommentID {get;set;}
    public int BlogID {get;set;}
    public string CommentContent {get;set;}
    public DateTime CommentDate {get;set;}
    public bool IsApproved {get;set;}

  }

以下是您的ViewModel;

  public class BlogViewModel { 

    public Blog Blog {get;set;}
    public IEnumerable<Comment> Comments {get;set;}
  }

当您为 BlogViewModel 类创建一个strogly类型的视图时,您可以按如下方式使用您的视图;

@model MyApp.BlogViewModel

<h2>@Model.Blog.Title</h2>

<p>
  @Model.Blog.Content
</p>

<div id="comments">

  <ul>

   @foreach(var item in Model.Comments) { 

    <li>@item.CommentContent</li>

   }

  </ul>

</div>

要使该视图健康,您的控制器需要将BlogViewModel对象传递给视图,如下所示;

  public ActionResult Blog(int id) { 

    //this is just an example here.
    //you need to put your logic here to get single Blog model
    var blogModel = myBlogRepo.GetSingleBlog(id);

    //this is just an example here.
    //you need to put your logic here to get IQueryable<Comment> model
    var commentsModel = myCommentRepo.GetAllCommnetsForBlog(id);

    BlogViewModel model = new BlogViewModel();
    model.Blog = blogModel;
    model.Comments = commentsModel;

    return View(model);

  }

这种情况是使用ViewModel最合理的情况。希望它有所帮助。

答案 3 :(得分:0)

ViewModel允许您的视图处理所需数据的类型化表示。此外,如果视图需要特殊计算(例如聚合多个子元素),它可能会触发您在视图中看不到的一些事件,例如,如果object-grape是延迟加载的,则查询数据库等。 ..在Service / Controller / Whatever层中构建ViewModel可以避免这些问题

如果您发现ViewModel很难创建,我建议您使用Automapper之类的工具来帮助您将Model对象映射到ViewModel对象。

简而言之,是的,Asp.Net MVC和ViewModels携手并进:)

答案 4 :(得分:0)

在我看来,MVVM存在的真正原因是:在某些技术中使用ViewModel,例如WPF,它与模型的视图互操作性有限。由于ViewModel是作为中间体创建的,以使模型对View更友好。

例如:在Model中你有一个简单的变量,但是在View中(对于WPF视图在大多数情况下由XAML表示)你需要一个依赖属性。 ViewModel作业是将Model变量公开为依赖属性。

如果你有可能在Model和View之间绑定数据,那么ViewModel会失去它的用处。

答案 5 :(得分:0)

我通常有3层课程。首先是ApplicationName.Domain,它包含POCO对象。这些是ORM用于持久化它们的实体(通常在数据库中)。第二组类驻留在MVC应用程序模型文件夹中。这是使用控制器内的AutoMapper映射的。然后第三组类在MVC应用程序ViewModels文件夹中。最后一个用于将@model传递给视图。

解释结构。

  • POCO对象不应该对表示有任何了解。但是,他们应该了解数据规则。我使用RequiredAttribute或StringLengthAttribute等属性来装饰POCO对象。
  • MVC应用程序中的模型应该知道每个属性的显示方式。我从POCO类中自动映射模型,并使用DisplayAttribute和类似的属性来装饰它们。
  • 由于UI还需要了解验证以显示验证错误,因此您必须在POCO和模型之间共享数据规则属性。您可以使用Meta类来完成此操作。例如,POCO类User和Model类UserModel都共享一个MetaClass属性,链接到UserMetaData。这可以为MVC应用程序和数据库层验证实现完全相同的规则。
  • 但是,当需要将一些非常复杂的数据传递给视图时,会使用ViewModels类。按照上面的例子,我会使用UserViewModel,如下所示:

    公共类UserViewModel {     public UserModel User {get;组; }     public IEnumerable {get;组; }     public int? SelectedRoleId {get;组; } }

在控制器中编译视图模型。角色集合不是实际的POCO对象,而是模型,因为您可以使用

自动映射这些对象
var roles = _roleService.GetAll();
AutoMapper.Mapper.Map<IEnumerable<Role>, IEnumerable<RoleModel>>(roles);

无论如何,简而言之,Models和ViewModels背后的想法是你可以构建你的整个应用程序,而不必担心持久性(对象存储),并在以后担心它。

答案 6 :(得分:0)

您使用与演示相关的内容装饰您的域对象。例如:分页和类别

ProductsListViewModel productsListViewModel = new ProductsListViewModel {
        Products = _repository.GetAll(),
        PagingInfo = new PagingInfo {
            CurrentPage = page,
            ItemsPerPage = PageSize,
            TotalItems = _repository.GetAll().Count()
        },
        CurrentCategory = category
    };

答案 7 :(得分:-1)

MVC中的M不代表查看模型,它代表模型。模型可以是一个ViewModel,但它也可能是一个域模型。

我所做的是我总是使用域模型,特别是对于简单的crud操作。然后,当需要额外的表示逻辑时,我将添加一个包含表示逻辑的ViewModel。恕我直言,这符合YAGNI原则。只需确保您的域模型不包含任何表示逻辑,并从中继续。