Friday, 14 October 2011

Using Data Annotations and Validators with the Entity Framework

After a lot of searching around, i finally found the answer.

Because when you use an ORM like Entity Framework, your Model objects will often get clobbered whenever you change the Model in the Designer and it re-generates your classes for you.

As a result of this, you cannot apply any Data Annoation directly to the generated classes.

This post and this one by Scott Gu explains that the technique you need to employ is 'buddy classes'.

What i didn't understand is: what was the point of applying the MetadataType attribute to the generated class??? It would just get over-written as well!

What i think Scott fails to make clear is: you need to add a new, seperate, partial class and apply the MetadataType to that (the new class is 'partial to' the generated Entity class) - DO NOT apply the MetadataType to the generated class!

All that's mentioned is:

"...apply a “MetadataType” attribute to a partial class that is compiled with the tool-generated class"

Example speaks a thousand words:

Lets say we're using Database First approach (or Model first) and we have a Person entity which is generated automatically for us every time we update the *.EDMX file in the Visual Studio Data Model Designer.

So we need to add a new partial class called 'Person' to the solution (making sure it is in the same namespace as the generated 'Person' class)

Right click on the Project > Add > Class

Call it 'Person.cs'

Change the declaration of the class to have the 'partial' keyword.

Add another class to the same file (or a new physical file, doesn't matter) - lets call it Person_Metadata.

Then add the MetadataType attribute to the new partial Person class.

My Person.cs file now looks like:

namespace BusinessDomain
{
    [MetadataType(typeof(Person_Metadata))] 
    partial class Person
    {
        // You can put custom business logic in here too!
    }
    class Person_Metadata
    {
        [Required]
        public object Name
    }
}


VIOLIA! The Name property of the Person object now has the 'Required' attribute applied to it and this WILL NOT be over-written when you update your Model via the Designer.

NOTE: The return type of the 'Name' Property is 'object' because it allows you to change the Type of the Property within the Model without having to update the Person_Metadata class eg if you wanted to change Nullable Boolean to Boolean, etc. You should retain this strategy for all properties you put in the Metadata class.

You can continue to add various Properties to the Person_Metadata class and assign them various Data Annotations.

No comments:

Post a Comment