Automatic Generation of Metadata "Buddy" Classes

MvcScaffolding.EntityMetadata is now available on NuGet.  EntityMetadata generates metadata classes for you with attribute-based annotations to denote things like max length, human-readible display names, nullable fields and more.  These classes are used to decorate your entity with a MetadataType attribute, giving you great labels on your views with only a few extra keystrokes.  EntityMetadata gives you a custom scaffolder – ControllerWithEntityMetadata – to use and then calls the regular Controller scaffolder that you would normally call.

How To Use It

Here's a quick step-by-step to use EntityMetadata from a new Asp.Net MVC 3 project:

  1. Add an EDMX (an Entity Framework designer file) to your project and add a few tables
  2. Right-click on the diagram and select "Add Code Generation Item..."
  3. Select the "ADO.NET DbContext Generator" item from the Data category
  4. Build your project
  5. In the Package Manager Console, type: Install-Package MvcScaffolding.EntityMetadata. This will check for and/or pull down EF, T4 Scaffolding, MvcScaffolding and EntityMetadata itself
  6. Still in the Package Manager Console, type: Scaffold ControllerWithEntityMetadata –Context YourContextNameHere (obviously replacing the last bit there with your context name). EntityMetadata will prompt you for the rest!

If you're having any issues, please see the FAQ at the bottom of this page, or visit the project page here and post comments/questions.

When To Use It

Here's the scenario: You are using database-first development with the Entity Framework and would like to make use of MvcScaffolding.  You think the only hiccup in your journey is that MvcScaffolding isn't too fond of the context and classes that are generated for you.  Thankfully the Microsoft folks have taken care of the juicy bits for us and created the DbContext custom code template.

All good, right?

Except that all our views seem to be scaffolded in a not-so-human-friendly way and don't know anything about max length or required.

image

The recommended way to fix this is to create a metadata class with all the same fields as your entity. You attribute each of these fields with the appropriate attributes from ComponentModel & DataAnnotations, setting up things like friendly names, whether or not fields are required and max length properties.  Finally, you create a partial class for your main entity and decorate it with the MetadataType attribute, specifying your metadata class.

And you have to do this for each entity in your model.

But we now have access to MvcScaffolding.EntityMetadata, available through NuGet, so all you need to do is type (or use tab-completion to help):

image

...and you'll see this:

image

...and your view will look like this:

image

...and more importantly, you'll have a Metadata class (with the required partial for the main class) generated for you here:

image

...which looks something like this:

image

There are a few things to point out that make this worth considering:

  1. These are created on-demand and can be created inline when you're scaffolding controllers
  2. These are not overwritten (unless you scaffold them again with –Force)
  3. You are free to edit this, rename, make changes as you see fit
  4. It's hella fast and takes the tediousness out of having to create the 'buddy' classes for your entities
  5. You can call EntityMetadata even after you've scaffolded the view and your view will immediately take advantage of the newly provided metadata.
  6. It does it's best to appropriately put human-friendly DisplayNames

 

Here's the FAQs

I don't have this DbContext code generation item you're talking about. Where do I get it?

Chances are you haven't installed the latest full bits of the Entity Framework, which you can get from MSDN.  This installs the DbContext template, a much more POCO-ish code generator than the standard ObjectContext.

I'm getting errors about multiple primary keys with the same name. What is wrong?

Chances are the compiler's just got confused with a couple different versions of the same entity class name, like the one originally created with the ObjectContext on your Edmx.  Clean your solution and rebuild.

Is there a shorthand version so I don't have to follow the prompts?

Yes, just follow the same order as the prompts and you'll be fine (so, type Scaffold ControllerWithEntityMetadata YourDbmxFilename YourEntityname)

Why does my database appear to have no data in it when I know it does?

You didn't specify the –Context argument to the scaffolder.  Check the instructions in the walkthrough up the page a bit.  Because EF 4.1 has code-first capabilities, and because MvcScaffolding will try to make up its own DB context, you've likely gone and created a new DB in either SqlCompact or SqlExpress on localhost.

Why can't it find my EDMX file?

Right now, EntityMetadata just assumes it's in your Models folder. Sorry, best I could do!

What if I need more help?

Please pop over to the project page and ask questions/add comments/demand features. Winking smile

11 Comments

  • Don Stavneak said

    This is great... thanks for providing! I found a problem with the command, it should be Scaffold ControllerWithEntityMetadata. But other than that, I've found it to work wonderfully with my style of MVC development.

  • Edo said

    Heya, good stuff, looks to be *exactly* what I needed. Unfortunatly I get this error. The views templates all render beautifully, but not the Metadata template:

    Attempting to create metadata for paymentserviceproviders in payratoradmin ...
    Invoke-ScaffoldTemplate : Failed to render template
    At line:1 char:23
    + param($c, $a) return . <<<< $c @a
    + CategoryInfo : NotSpecified: (:) [Invoke-ScaffoldTemplate], Exception
    + FullyQualifiedErrorId : T4Scaffolding.Cmdlets.InvokeScaffoldTemplateCmdlet

    Add-ProjectItemViaTemplate : error : Running transformation: System.InvalidOperationException: Sequence contains no elements
    at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
    at Microsoft.VisualStudio.TextTemplating02D96D49E56070EE3F665ECF3444ECDC.GeneratedTextTransformation.TransformText()
    at Microsoft.VisualStudio.TextTemplating.TransformationRunner.RunTransformation(TemplateProcessingSession session, String source, ITextTemplatingEngineHost host, String& result)
    At D:\Work\SVNRoot\payrator\trunk\PayRatorAdmin\CodeTemplates\Scaffolders\EntityMetadata\ControllerWithEntityMetadata.ps1:19 char:27
    + Add-ProjectItemViaTemplate <<<< $outputPath `
    + CategoryInfo : NotSpecified: (:) [Add-ProjectItemViaTemplate], Exception
    + FullyQualifiedErrorId : T4Scaffolding.Cmdlets.AddProjectItemViaTemplateCmdlet

  • james.chambers said

    Thanks for the head's up.

    Is there any chance you'd be willing to share the part of the EDMX that is causing the error? I'll try to beef up error handling there if I can figure out what's going on.

    Alternately, if you have any details on the table in question that might be "not the norm" I can try to work through that.

    Cheers, and thanks for trying it out!

  • Buddy Stein said

    I use the mvcscaffolders a lot and I really like your metadata scaffolder. I want to implement a data annotation [Ignore] so that the mvcscaffolders ignore fields that I tag.

    How would you implement this?

  • Buddy Stein said

    I find I always have to add [Key] to my generated dbcontext partial class, even though my ID names are like PartId.

    Any idea why this happens.

  • james.chambers said

    Thanks, Buddy, glad it's helping you out!

    How are you tagging the fields? This version of the scaffolder uses the EDMX to read metadata from. Is it stored in there somewhere?

    I had trouble with the ID/Id thing once upon a time, but not running into that right now. Can you try if it's a caps thing (ID versus Id)? That's not a fix, but if it works...

    I prefer and use the same style you're using (PartId), but I'm not sure why it's missing it.

    Check to make sure that the PartId field was properly generated on the EDMX; it might not be marked as the key.

    Hope this helps some.

    Cheers!

  • Aki Siponen said

    Hi,

    This seems to be a great tool. Just the thing I've been looking for.

    I'm using VWD 2010 Express and VB.NET and decided that I could convert EntityMetadata for VB.

    Unfortunately I ran into errors immediately. I tried to isolate the errors and this is what it seems to amount to:

    Template EntityMetadataHelperTemplate.vb.t4 containing:
    <#@ Template Language="VB" Debug="false" HostSpecific="true" Inherits="DynamicTransform" #>
    <#@ output extension=".vb" #>

    Public Class whatever
    End Class

    works fine.

    But whenever I add the line
    <#@ include file="EF.Utility.VB.ttinclude" #>

    to the template, I get an error:
    System.ArgumentException: Property ReferencedAssemblies cannot contain null values or empty strings.
    Parametrin nimi: options
    in Microsoft.VisualBasic.VBCodeGenerator.CmdArgsFromParameters(CompilerParameters options)
    ...[Stack trace]...

    Of course I copied the file EF.Utility.VB.ttinclude to the CodeTemplates\Scaffolders\EntityMetadata folder in my project.

    I've been trying to figure out what's the reason, but haven't found any reasons for this.

    I'm using EF 4.1, database first, DbContext Code Generator, which works just fine.

    Any suggestions where I should start searching the problem?

  • Steve said

    This looks like it would be a great addition to a project I'm starting, but I'm having trouble using it. Do you know if it works with MVC4? I get this error: Invoke-Scaffolder : A parameter cannot be found that matches parameter name 'Context'.

  • Steve said

    I found the error - in two places you show "Scaffold ControllerWithMetadata..." and in one, you show the correct "Scaffold ControllerWithEntityMetadata..." So, once I caught onto that, it ran. However, I'm now getting: Get-PrimaryKey : Cannot find primary key property for type 'MvcApplication7.Mod
    els.Role'. No properties appear to be primary keys.

    Where should I be looking to figure out what is wrong. The EDMX shows Role_PK to have the Entity Key property set to True.

    Any help would be appreciated. Thanks.

  • james.chambers said

    Steve, are you still having issue with this?

    If you re-evaluate the table/entity in question, does the PK identified on the table match the one in the EDMX?

Add a Comment