Saturday, October 1, 2011

Defining metadata for Entities created using Entity Framework

Ive been using Entity framework for a couple of months now. I had this issue a while back, where I had an entity model designed using the entity framework designer  (note: I am currently using the 4.1 update). My task was to extend the entity model so that I could decorate an entity class with some data annotations.

For the sake of simplicity, let us assume that our entity data model has only the following entity, Product, defined like so:

If this product class was used, say as a model for an MVC3 controller, calling an html helper method to automatically render an editor for the model, (as shown below):


@model MyDomain.Entities.Product
 
@{
    ViewBag.Title = "Edit";
}
 
<h1>Edit @Model.Name</h2>
 
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="save" />
}

However this would result in the view being rendered with an html input element for each data member of the Product entity, including the Id field (of type int) which also happens to be the primary key. This may not be desired, as typically users should not be able to control setting the primary key for an entity. However we cannot simply extend the partial class and overwrite the field either. We could simply edit the code generated by EF for the Product EntityObject class, but any changes to the model would result in your data annotations being wiped, so this is not recommended either. As such the easiest way to solve this issue is to decorate your entity class with the System.ComponentModel.DataAnnotations.MetadataTypeAttribute 






First, we create a new class called ProductMetaData within which we define a single property called Id. Notice that the Id property is defined to be the same type as that of the Id field in the Product entity object, i.e. they are both of type Int. Once this is done, we can add a data annotation to instruct MVC's html helper methods to omit this field when rendering the view (note I am using the HiddenInput data annotation defined in the System.Web.Mvc namespace for this example):


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace MyDomain.Entities.Metadata
{

    public class ProductMetadata
    {
        [HiddenInput(DisplayValue=false)]
        public int Id { getset; }
    }
}


Following this, we can then simply create a partial class for the entity that we wish to annotate, in this case the Product entity. Once this is done, all that is left is to annotate the class with a MetadataTypeAttribute, passing in the type of the ProductMetaData class in the constructor and recompile.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MyDomain.Entities
{
    [MetadataType(typeof(MyDomain.Entities.Metadata.ProductMetadata))]
    public partial class Product
    {
 
    }
}


And that's basically it. During runtime, the html helper methods will now omit generating an editor for the Id field every time the view is rendered like so:




No comments:

Post a Comment

Feel free to provide any feedback