5

无论我使用 Automapper 还是手动映射,都不起作用。

ReleaseViewModel 的所有数据都必须在 Release 中排在第一位,因为它是在数据访问层中填充的。我的模型 90% 都是这样的。为什么复制所有内容的开销?

KISS 原则和过度设计又如何呢?

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

在哪里画线?当 ViewModel 与我的模型区分为 50%、75% 或 99% 时,我应该使用它们吗?

我有一个模型发布:

 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; }
    }

视图模型 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; }
}
4

5 回答 5

5

ViewModel是用于VIEW的东西。大多数时候它类似于您的实体模型。但不总是。

看看你的例子。在您的ViewModel中,您有RemoteAttribute 和一些 Validation 属性。因此,此远程名称检查是您添加的内容,旨在为您的用户提供更好的用户体验。它特定于视图。

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

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 真正需要它时创建它。我有时在某些视图中直接使用我的模型实体对象而不创建视图模型,因为它们完全相同。例如:国家/州/城市(查找表格数据。无添加/编辑)

于 2012-06-26T19:34:54.627 回答
2

为什么复制所有内容的开销?

首先,你可能认为我在复制代码,但事实是你不是,如果你这样做,你有一个严重的设计问题

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

可能是因为您还没有发现问题,或者您已经找到并且您刚刚修补了代码。您的域对象的职责与将数据呈现给用户的职责完全不同。

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

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

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

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

于 2012-06-26T19:39:50.743 回答
1

我的 ViewModel 只是简单地包装了一个模型,并在 90% 的时间里委托给它。只有当我需要针对特定​​视图用例更改模型行为时,它们才有自己的行为。拥有虚拟机确实可以更轻松地添加仅用于显示目的的行为,特别是如果该行为会干扰您的持久性模型(例如添加您希望持久化的属性)。

还值得注意的是,很有可能使用 Castle 或 SpringFramework.net 等 IoC 工具即时生成默认转发行为,从而减少您需要手动编写的代码量。这相当显着地降低了“重复成本”,因此并没有最初看起来那么糟糕。

于 2012-06-26T19:08:41.077 回答
0

我支持 Shyju 所说的一切,尤其是关于“当你需要它的时候”的部分。

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

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

请记住,当您在 Web 项目中重用 EntityModel 类时(即,将它们用作存储模型和表示模型),您正在创建项目的 Web 方面和项目的业务方面之间更紧密的耦合。如果你能因为成本/预算、时间、目标受众、范围或其他限制来证明这一点,那就去做吧,不要理会你的批评者,因为他们没有像你一样看到全局。

于 2012-06-26T19:52:00.733 回答
0

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

于 2012-06-27T11:37:09.833 回答