【问题标题】:MVC architecture - re-using the same viewmodel for reads and editsMVC 架构 - 重复使用相同的视图模型进行读取和编辑
【发布时间】:2012-02-17 23:11:12
【问题描述】:

假设我们有以下(过于简单)的场景:

我们有一个用于查看人员详细信息的屏幕和一个用于编辑人员详细信息的屏幕。

屏幕显示人员详细信息有以下字段(仅作为显示):

名字 姓 简介

屏幕编辑人员详细信息显示具有以下字段(在输入控件中):

ID(隐藏) 名 姓 简介

假设我们的显示视图模型如下所示:

    public class DisplayPersonViewModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Bio { get; set; }
    }

我们的编辑视图模型看起来像这样:

public class EditPersonViewModel
{
    [Required]
    public int ID { get; set; }

    [Required]
    [StringLength(20)]
    public string FirstName { get; set; }

    [Required]
    [StringLength(20)]
    public string LastName { get; set; }

    [Required]
    public string Bio { get; set; }
}

两者之间没有太大区别,是吗?编辑模型有一个额外的字段 (ID) 和一些属性上的属性。现在,如果我们要像这样组合 2:

    public class DisplayPersonViewModel
    {
        [Required]
        [StringLength(20)]
        public string FirstName { get; set; }

        [Required]
        [StringLength(20)]
        public string LastName { get; set; }

        [Required]
        public string Bio { get; set; }
    }

    public class EditPersonViewModel : DisplayPersonViewModel
    {
        [Required]
        public int ID { get; set; }
    }

这当然更 DRY,因为我们没有要维护的重复字段,但现在我们的显示视图模型上有无关的信息(属性)。无论如何,我更倾向于第二种方法,因为我们的某些屏幕有超过 25 个字段! (...这超出了我的控制范围,所以请不要喋喋不休:)...)但是,我只是想听听意见,以更好地了解什么可能是“最佳实践”。

【问题讨论】:

  • 是的,如果您正在开发一个包含许多模型的大型应用程序,每个模型可能有十几个或更多字段,该怎么办?随着应用程序的发展,您会不断添加字段。随着时间的推移,您如何使本质上相同实体的多个视图模型保持同步?

标签: asp.net-mvc model-view-controller architecture viewmodel


【解决方案1】:

是的,第二种方法对我来说似乎很好。除了胃里的痒感告诉你你到底为什么要用验证属性装饰一个显示视图模型之外,别担心。但如果你能接受它,与复制视图模型相比,它确实是首选。

不幸的是,我个人无法忍受这种感觉,这就是为什么我使用FluentValidation.NET 来定义我的验证规则而不是数据注释。它允许我将这些规则与我的视图模型分开,然后我不用担心用验证规则污染所谓的显示视图模型。因此,我会以与您相同的方式定义 2 个视图模型,EditPersonViewModel 将派生自 DisplayPersonViewModel,然后在单独的类中为 EditPersonViewModel 定义我的 EditPersonViewModelValidator

哦,附​​带说明:不需要使用 [Required] 属性装饰不可为空的类型。所有不可为空的类型都是必需的,因为它们的基本性质。所以而不是:

[Required]
public int ID { get; set; }

你应该只有:

public int ID { get; set; }

【讨论】:

  • 是的,我正要看看那个。它是否适用于客户端不显眼的验证?另外,你能创建一个带有自定义客户端验证的自定义验证器吗?
  • @drogon,它支持与数据注释相同的客户端验证规则以及更多:fluentvalidation.codeplex.com/…
【解决方案2】:

另一种选择是使用MetadataType 属性。

public class PersonModel
{
  public int ID { get; set; }   
  public string FirstName { get; set; }  
  public string LastName { get; set; }   
  public string Bio { get; set; }   
}

[MetadataType(typeof(IDisplayPersonViewModel))]
public class DisplayPersonViewModel : PersonModel

[MetadataType(typeof(IEditPersonViewModel))]
public class EditPersonViewModel : PersonModel

public interface IDisplayPersonViewModel
{
  [ScaffoldColumn(false)]
  public int ID { get; set; }   
}

public interface IEditPersonViewModel
{
  [Required]                
  [StringLength(20)]                
  public string FirstName { get; set; }                

  [Required]                
  [StringLength(20)]                
  public string LastName { get; set; }                

  [Required]                
  public string Bio { get; set; }                

  [Required]                
  public int ID { get; set; }             
} 

您的原始 Person 模型是无属性的。您的 Display 和 Edit 模型仅具有视图实际需要的属性。

【讨论】:

  • 这样做的缺点是您仍然必须维护所有这些属性定义
  • 同意,但是您没有与特定显示器或验证相关联的模型。您仍然可以使用任何验证“插件”并创建多种显示类型,而无需触及原始模型。
  • 你干得很好。说真的。从过去的 10 天开始,我一直在寻找此类问题的解决方案。谢谢!!!! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多