我仍然犹豫使用ViewModels而不是View for Model

时间:2012-06-26 19:05:01

标签: asp.net asp.net-mvc mvvm viewmodel

我使用Automapper或手动映射,它不起作用。

ReleaseViewModel的所有数据必须是Release中的第一个,因为它在数据访问层中填充了它。 90%的模特都是这样的。为什么要复制一切的开销呢?

KISS原则和过度工程怎么样?

当然,每个工具都适合其适当的任务,但我经常读到,在asp.net mvc中不使用ViewModel是NO-GO。

在哪里划线?当我们从模型中区分到50%,75%或99%时,我应该使用ViewModels吗?

我有一个模型发布:

 public class Release
    {      
        public int Id { get; set; }       
        public string Name { get; set; }
        public string Author { get; set; }
        public DateTime CreatedAt { get; set; }
        public int FailedTestsCount { get; set; }
        public int SucceededTestsCount { get; set; }
        public int SumTestsCount
        {
            get
            {
                return SucceededTestsCount + FailedTestsCount;
            }
        }
        public int SumTestingTime { get; set; }
    }

viewmodel ReleaseViewModel:

public class ReleaseViewModel
{
    [HiddenInput(DisplayValue = false)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Name must not be empty.")]
    [StringLength(30, ErrorMessage = "Enter max. 30 chars for a name.")]
    [Remote("ReleaseExists", "Release", ErrorMessage = "This name already exists.")]
    public string Name { get; set; }    
    public string Author { get; set; }    
    public DateTime CreatedAt { get; set; }    
    public int FailedTestsCount { get; set; }    
    public int SucceededTestsCount { get; set; }    
    public int SumTestsCount 
    {
        get
        {
            return SucceededTestsCount + FailedTestsCount;
        }
    }

    public int SumTestingTime { get; set; }
}

5 个答案:

答案 0 :(得分:5)

ViewModel适用于 VIEW 。大部分时间它与您的实体模型类似。但并非总是如此。

看看你的例子。在ViewModel中,您拥有Remote属性和一些验证属性。因此,您可以添加此远程名称检查,以便为用户提供更好的用户体验。它特定于View。

您需要Viewmodel的另一个场景是适用于涉及多个模型的屏幕。例如:您有一个User实体和一个Project实体,并且您希望提供一个可以将项目添加到用户的屏幕。所以在这种情况下,您可以创建一个viewmodel来处理

public class ProjectToUserVM
{
  public int UserId { set;get;}
  public string UserName { set;get;}  // i want to display only name of user!
  public int ProjectID { set;get;}
  public IEnumerable<SelectListItem> Projects { set;get}
}

不要将ViewModel用于所有模型实体。当您的VIEW确实需要时创建它。我在一些视图中直接使用我的Model实体对象而不创建一个viewmodel,因为它们完全相同。例如:国家/州/市(查找表数据。无添加/编辑)

答案 1 :(得分:2)

  

为什么要复制一切的开销?

首先,你可能会认为我正在复制代码,但事实是你不是,如果你这样做,你就会认真对待设计问题

我发现有一个原则,当你不遵循它时,它确实是万恶之源:SRP(单一责任原则)

也许是因为你还没有找到问题,或者你可能已经修补了你的代码。 您的域对象的责任与向用户呈现数据的责任完全不同。

MVC中的模型应该是一个表示视图需要呈现的所有数据的类,而不是。您需要使用域中的数据填充此模型。 (或在CQRS架构中,来自您的查询服务)

如果你遵循CQRS架构(至少是基础知识,你不需要实现事件来源,也不需要使用服务总线来将命令与你的查询分开),这对你来说更明确,查询对象与命令对象(来自您的域的操作)完全不同

我认为你误解了KISS原则,虽然它说的是过度设计代码或YAGNI,但这并不意味着你必须重用应用程序中的所有内容

相信我,我学会了这个坏方法=(,唯一应该重用的代码是基础设施代码,在谈论域代码时,最好始终遵循SRP

答案 2 :(得分:1)

我的ViewModel只需包装一个Model,并在90%的时间内委托给它。当我需要针对特定​​视图用例更改模型的行为时,它们只有自己的行为。拥有VM确实可以更容易地添加仅用于显示目的的行为,特别是如果该行为会干扰您的持久性模型(例如,添加想要持久化的属性)。

值得注意的是,很有可能使用像Castle或SpringFramework.net这样的IoC工具动态生成默认转发行为,减少手动编写所需的代码量。这相当大地降低了“复制成本”,所以它没有最初看起来那么糟糕。

答案 3 :(得分:0)

我是Shyju所说的第二件事,特别是关于“何时需要它”的部分。

如果你有一个非常简单的项目,你的EntityModel类与ViewModel类位于同一个库中,你可能不需要单独的ViewModel dto并且可以放弃它们。我不认为任何智能人会告诉你“你做错了,因为你正在使用实体类来查看你的视图模型,dumass。”我们不知道您的应用程序的上下文是什么。在你的情况下,这可能是完全合适的。

我们中的一些人在非Web程序集中定义EntityModels - 只是一个编译成DLL的普通类库 - 用于大型项目。在这种情况下,我们经常需要将特殊属性应用于视图,例如示例问题中的RemoteAttribute和HiddenInputAttribute。但是,在不使用单独的viewmodel dto层的情况下执行此操作意味着我们必须将对System.Web.Mvc.dll的引用添加到EntityModel库,而实际上该库与Web无关“

请记住,当您在Web项目中重用EntityModel类(即将它们用作存储模型和演示模型)时,您正在创建项目的Web方面与您的业务方面之间更紧密的耦合。项目。如果你可以因为成本/预算,时间,目标受众,范围或其他限制而证明这一点,那就去做吧,而忽视你的评论家,因为他们没有像你那样看到那么大的画面。

答案 4 :(得分:0)

如果您的Release类实现了INotifyPropertyChanged以及视图所需的所有其他内容(验证,命令......),那么您不必使用viewmodel。但如果不是......