Search code examples
c#asp.net-mvcentity-frameworkmodeldata-annotations

Preserve DisplayName between code regeneration


I have created a database in SQL Server and have used Entity Framework to create a model in my C# MVC 5 project. In my models I am using System.ComponentModel to give a DisplayName to several properties (or columns). Example:

namespace ProjectTracking.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;

    public partial class EmployeeType
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public EmployeeType()
        {
            this.Employees = new HashSet<Employee>();
        }

        [DisplayName("Employee Type ID")]
        public int PK_EmployeeTypeID { get; set; }

        [DisplayName("Employee Type Name")]
        public string EmployeeTypeName { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Employee> Employees { get; set; }
    }
}

The problem that I've run into is that, if I update the database and update my model, I lose all of this information as all of the model classes are regenerated. Is there a way to persist this information?


Solution

  • EF is using T4 templates to generate the code. You should never edit these files, because they could be regenerated anytime when you open the designer.

    There is a way to do this, using the MetadataTypeAttribute`

    EF generates the models as partial classes, so you can add another part in a different file, which won't be regenerated and a the MetadataTypeAttribute to it. This will point to yet another class in which you can duplicate the properties and supply the DisplayNameAttribute. Like this:

    [MetadataType(typeof(EmployeeTypeMetaData))]
    public partial class EmployeeType  { }
    
    public class EmployeeTypeMetaData
    {
        [Required(ErrorMessage = "Title is required.")]
        public object Title;
    
        // etc
    }
    

    This would the job... However:

    You should not use this for the following reasons:

    • This will give you a maintenance nightmare. Any time your model changes you need to change the metadata also
    • You should never use your ef models directly in views of some kind. Use DTO objects in between and map between the ef models and the DTO. Mapping can be done either by hand of by a tool like AutoMapper