我正在使用 POCO 使用 EF4 创建一个 MVC3 应用程序。我已向我的 EF 实体添加了验证属性。现在,当我构建视图时,我想使用视图模型(并且可能使用AutoMapper来填充它们)。
我遇到的问题是我必须在我的视图模型上重新定义我的验证属性,这违反了 DRY 原则。例如,如果我决定更改字段的大小,我必须同时更改 POCO 和使用它的任何视图模型的 MaxLength 属性。
是否有一些棘手的方法可以将验证规则从我的 POCO 映射到我的视图模型?
我正在使用 POCO 使用 EF4 创建一个 MVC3 应用程序。我已向我的 EF 实体添加了验证属性。现在,当我构建视图时,我想使用视图模型(并且可能使用AutoMapper来填充它们)。
我遇到的问题是我必须在我的视图模型上重新定义我的验证属性,这违反了 DRY 原则。例如,如果我决定更改字段的大小,我必须同时更改 POCO 和使用它的任何视图模型的 MaxLength 属性。
是否有一些棘手的方法可以将验证规则从我的 POCO 映射到我的视图模型?
我个人在视图模型上执行验证。这是控制器从视图接收的内容,它是包含用户输入的类。我区分了两种类型的验证规则:表面验证和业务验证。诸如必填字段、正确格式之类的规则应在视图模型中强制执行,而诸如数据库中已存在具有给定名称的用户之类的业务规则应在模型上进行验证。
此外,您可以将不同的视图模型映射到同一模型,但基于视图验证规则可能会有所不同。因此,您不会在视图模型上拥有完全相同的验证规则。
获得一些抽象的一种方法是让您的业务模型类“组合”一个 ViewModel,包括您需要的其他视图信息。
class MyObject
{
public int ID {get;set}
[Required]
[StringLength(512)]
public string Name {get;set;}
}
class MyViewModel // ViewModel for a specific view
{
public MyObject MyModel {get;set;} // the model that is being edited
// other data the view might need, set by the controller
public string SomeMessage { get; set; }
public List<SomeObject> SomeObjects {get;set;} /// e.g. for a drop-down list
}
然后在视图中相应地引用 ViewModel。
@model My.Namespace.MyViewModel
Hello @model.MyModel.Name !!!
这样,您只需在一个地方指定您的业务类中的验证和/或数据注释。
如果您想要进行不同的验证,那么这将需要一些策略来选择性地应用验证逻辑。
我也为此苦苦挣扎,我同意它违反了 DRY。我最近在此处发布了一个关于此的问题,但遭到了相当多的反对。
在任何现实世界的应用程序中,您都无法获得完美的 DRY。有时,你从违反原则中获得的好处比试图盲目地坚持它要好。
编辑:
人们也可能认为 DRY 可能违反单一职责原则 (SRP)。通过重用类似的代码,您现在正在使代码做不止一件事。如果您考虑到数据模型和视图模型具有不同的目的,因此具有不同的职责这一事实……将它们组合成一个模型违反了 SRP。也就是说,通过使您的数据模型也成为视图模型,这是两个不同的职责。
现在,在这方面,人们可以想出多种方法来尝试协调 SRP 与 DRY,但在某些时候,您必须权衡成本带来的好处。