Is it possible to reuse the DataAnnotations in ViewModel?

社会主义新天地 提交于 2019-12-05 04:41:32

问题


In my MVC application, I defined the DataAnnotations in the domain models. Although the DataAnnotations properties as Display, etc. can be retrieved when using Domain model, they cannot be retrieved when using the same properties on ViewModel and using this ViewModel. I think it is not seem to good to define the DataAnnotations in ViewModel again. So, is it possible or which way should I follow?


Domain Model:

public class Issue
{
    [Key] 
    public int ID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Project Number")]
    public int ProjectID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Issue Definition")]
    public string Description { get; set; }

    //... removed for brevity

    //Navigation Properties:
    public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}


ViewModel:

public class IssueViewModel
{
    public int ID { get; set; }

    public int ProjectID { get; set; }

    public string Description { get; set; }

    //... removed for brevity

    //Navigation Properties:
    public virtual ICollection<FileAttachment> FileAttachments { get; set; }      
}

回答1:


You can create a new buddy class which holds all metadata about properties and class.

public partial class IssueMetadata
{
    [Required(ErrorMessage = "Required")]
    [Display(Name = "Project Number")]
    public int ProjectID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Issue Definition")]
    public string Description { get; set; }
}

Then, we must tell the MVC Framework about the buddy class through the MetadataType attribute, which takes the type of the buddy class as its argument. Buddy classes must be defined in the same namespace and must also be partial classes.

[MetadataType(typeof(IssueMetadata))]
public partial class IssueViewModel
{
      //...

      public int ProjectID { get; set; }
      public string Description { get; set; }

      //...
}

[MetadataType(typeof(IssueMetadata))]
public partial class Issue
{
      [Key] 
      public int ID { get; set; }

      public int ProjectID { get; set; }
      public string Description { get; set; }

      //... removed for brevity

      //Navigation Properties:
      public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}

Additional note:
If IssueMetadata and Issue (or IssueViewModel) classes located in different assemblies, then you can associate classes with their buddy class in runtime, like that:

public class AssociatedMetadataConfig
{
    public static void RegisterMetadatas()
    {
        RegisterPairOfTypes(typeof(Issue), typeof(IssueMetadata));
        RegisterPairOfTypes(typeof(IssueViewModel), typeof(IssueMetadata));
    }

    private static void RegisterPairOfTypes(Type mainType, Type buddyType)
    {
        AssociatedMetadataTypeTypeDescriptionProvider typeDescriptionProvider 
          = new AssociatedMetadataTypeTypeDescriptionProvider(mainType, buddyType);

        TypeDescriptor.AddProviderTransparent(typeDescriptionProvider, mainType);
    }
}

And, just call this static method in global.asax:

AssociatedMetadataConfig.RegisterMetadatas();



回答2:


@StephenMuecke is right. DomainModel attributes and ViewModel attributes are different and you can use them seperately in your models. But I would use inheretence in this case, if I were you. You can create a Partial class for ViewModel and inherit your DomainModel from this ViewModel class.

Like:

public class IssueVM
{
    [Key] 
    public int ID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Project Number")]
    public int ProjectID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Issue Definition")]
    public string Description { get; set; }

    //... removed for brevity

    //Navigation Properties:
    public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}

public class IssueDM : IssueVM
{
    // Other Fields
}

That way you have a base class of ViewModel (less fields) and a larger class with more fields for DB operations. Your ViewModel data annotation attributes are also inherited in your DomainClass that way.

I don't claim that this is the best way, but I'am using this and works fine.



来源:https://stackoverflow.com/questions/31048530/is-it-possible-to-reuse-the-dataannotations-in-viewmodel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!