Add Data Annotations to Entity Framework Models with Metadata or Buddy Classes

When using code generation (ORM), the model classes are automatically created by the tools.  We usually try to edit the class and add annotations such as field requirements, formatting and messages. The problem with this approach is that when we need to add properties to the model class, we will need to re-generate the class and all the data annotations will be wiped out which create extra work for us.

A quick way to address this challenge is to create a Metadata or Buddy class that provides all the annotations that we need. We can then add an attribute to a partial class with the same name as the class that was generated to indicate that there is another class that provides the annotations on its behalf.   We can now take a look at an ASP.NET MVC project which can be loaded from the source code link at the end of this article.

Class Generated by Entity Framework (Database first approach)

We first create a simple table with the following definition:

CREATE TABLE [dbo].[Car] (
    [Id]    INT           IDENTITY (1, 1) NOT NULL,
    [Make]  NVARCHAR (50) NOT NULL,
    [Model] NVARCHAR (50) NOT NULL,
    [Trim]  NVARCHAR (50) NULL,

Note: This table is created using the .mdf files under the app_data folder.

We now can use EF by adding an ADO.Net Entity Data Model to create the model from our database which generates the following definition (see Models/car.edmx file). Do not forget to compile after the table has been imported.

namespace og.samples.aspnet.MetaDataClass.Models
    public partial class Car
        public int Id { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
        public string Trim { get; set; }        

As we can see, there are no annotations on this model. Since this is a generated class, we would like to add our annotation class instead of changing it. We need to do this before we generate the views.

New Partial and Metadata Classes

The steps to add our metadata class are the followings:

1)      Add a new class under the model folder
a.      Name it  car.metadata.cs
2)      Create another class that contains all the data annotations.
a.      This is not a partial class
b.      This is a sealed class as there is no need to instantiate it
3)      Add a new partial class with the same name as the ORM class
a.      Add the [MetadataType] attribute to the class that was just created
b.      Set the type to the class that has the annotations.
4)      Compile

The code should now look as follows:

namespace og.samples.aspnet.MetaDataClass.Models
    /// <summary>
    /// partial class definition to associate the ORM generated class
    /// NO NEED to add the properties here.
    /// </summary>
    public partial class Car

    /// <summary>
    /// Buddy Class or Data Annotation Class
    /// Add the properties here with the associated annotations
    /// </summary>
    internal sealed class CarAnnotation
        [Required(ErrorMessage="{0} is required")]
        [MinLength(3,ErrorMessage="{0} should have three or more letters")]   //kia
        public string Make { get; set; }

        [Required(ErrorMessage = "{0} is required")]
        public string Model { get; set; }
We are making Make and Model required. In addition, we are making the Make to have a minimum of three characters.

Create Controller and Views

We now just need to add our controller and views by adding a controller item under the controller folders and selecting the following properties:
  1. MVC 5 with controller with views, using Entity framework
  2. Enter the following settings and compile the project

 Cars Create View (see sample project)

Run the application and select Run Demo under the Metadata classes section.

This is how the view should look. Press Create for the validation to take place as shown below.

With the above view, we can show that our data annotation validations are shown when the user does not meet the input requirements.


With this approach we can show that we can still enable the use of ORM tools to generate the models and continue to support our application specific data annotation requirements without the concern of losing any information.

Code Sample

Available at:  GitHub  (see Dev Branch for latest changes)



Post a Comment

What do you think?