Friday, March 12, 2010

Entity Framework Code Generation Template

Well, I should probably have waited until I understand it better, but I was so excited when I found out how easy it was that I had to post it right away.  What am I babbling about?  It is Visual Studio 2010's support for "T4" code generation templates.  At first I was pretty intimidated by this topic (especially since they named it after one of the Terminator models...shudder), but it turns out there is nothing to fear but fear itself.  So here goes...

Adding a T4 Template to Your EF Project
A couple of posts ago I discussed what, in my opinion, is a big hole in EF binding and change notification.  Specifically, no PropertyChanged/ing events get fired when changing an association with another entity in the model.  For example, if a Trip entity has a reference to a Destination entity in a property called "Destination" and you change which Destination instance that property is pointing to no PropertyChanged/ing events are fired. None whatsoever.  In my post I mentioned that this could probably be solved with a code generation template.  I can now cross out the word "probably." The first step is to add such a template to your EF project (i.e., a project that already has a *.edmx file). Right-click on your project and from the context menu select Add/New Item...


Choose the "ADO.NET EntityObject Generator" from the Code node.  Rename this to whatever you want (I chose the same name as my *.edmx file).  This will add a *.tt file to your project.  The bad news is that VS 2010 does not appear to offer any code coloring or intellisense for these files so they can look a little intimidating at first.  If you want to make big changes then you need to find another blog.  We're starting slow here.

Oh, Great a New Syntax to Learn.  Yippee.
So what you will see as you are browsing the *.tt file is a lot of C# code sprinkled liberally with some additional syntax and a few comments.  As your eyes adjust you might be pleasantly surprised to find that, in fact, 90% of what you see looks like C# code.  Then you notice that some of the C# code seems to be bracketed by "<#" and "#>".  This appears to be what separates the code-generation C# from the actual generated-code C#.  Basically, anything on the inside of a <# ... #> is the logic that governs the code generation process and code not enclosed in these delimiters is the actual code that will be in the resulting *.cs file.

Enough gawking. Search for the place in the file that has string "Reference" (including the quotes).  The section immediately above this word should be as follows with the exception of the highlighted parts, which need to be added by you.

    <#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForPro...;
    {
        <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get
        {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedRefe...;
        }
        <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set
        {
            OnPropertyChanging("<#=navProperty.Name#>"); 
             ((IEntityWithRelationships)this).RelationshipManager.GetRelatedRefer...;
            OnPropertyChanged("<#=navProperty.Name#>");
        }
    }


After adding these two lines, save the file.  You will notice two things that you have a generated *.cs file underneath your *.tt file.  If you try to view your old *.designer.cs file that was under the *.edmx file you will get a warning message and the file will be empty.  That is because your new *.cs file has taken it's place.  If you open it and look at the navigation properties, you will notice that the setters now fire the PropertyChanged/ing events.  No more need for the old work-around.  If you have any of the old code from the previous post, delete or comment it out and run your project.  Binding updates due to EntityReference changes should happen now without the work-around code.  Cool.

No comments:

Post a Comment