Dynamic Data and the Associated Metadata Class

If you've used Dynamic Data or watched some demos, you may have been puzzled by the way metadata is associated with database fields.  Instead of being placed directly on the partial Entity class (e.g. Product), it needs to go on a different class which gets associated with the real class via a MetadataTypeAttribute.

Here is an example where we're adding a display name on the UnitsInStock column:

 [MetadataType(typeof(Product_Metadata))]
public partial class Product {
}

public class Product_Metadata {
    [DisplayName("The Units In Stock")]
    public object UnitsInStock { get; set; }
}

Here are the key pieces at play:

  • First you have the Product partial class, which is 'partial' with the Product class that was generated by the Linq To Sql or Entity Framework designer.  The generated class contains the 'real' UnitsInStock property, which is an integer (not shown above, but you'll find it in the generated Northwind.designer.cs file).
  • This partial Product class has a MetadataType attribute pointing to a different class called Product_Metadata (the name is arbitrary but appending _Metadata is a good convention to indicate a MetaData buddy class).  This is the metadata class, sometimes referred to as the associated class or the 'buddy' class.  Note that this class only exists to hold metadata, and is never instantiated.
  • On the metadata class, there is a UnitsInStock property.  This is sort of a 'dummy' property that is used as a place to put CLR attributes on.  We typically give it a return type of 'object', though in reality it is ignored and could be any type.
  • And finally there is the metadata attribute itself, in this case DisplayName (and obviously you could have more than one attribute).

Why are we doing this?

So I have described what we do, but not really why we do it this way, instead of putting attributes directly on the real property.  Simply stated, the reason is that it's not possible, due to a C# language limitation (VB.NET has the same issue).  The limitation is that when one half of a partial class defines a property (in this case it's in the generated class), you cannot add attributes to that property from the other half of the partial class (in this case in the user code).

Of course, you could easily add the attributes directly on the generated class where the property is defined, but that would be a very bad idea, because you would lose it all as soon as you make a model change that requires the file to be regenerated.  In general, you should never make any changes to generated files, as that is asking for trouble!

What if you don't want to use CLR attributes for your metadata?

Some users don't like using CLR attributes on their entity class to define their metadata.  To see an alternative technique that lets you keep your metadata in arbitrary places, check out this really cool post by Marcin (one of the developers on Dynamic Data).