Jeff Sheldon

Mostly.NET
posts - 15, comments - 1, trackbacks - 0

Entity Framework – T4 Template Happiness

 

I was going to make this one long post, but there’s just too much to cover.   I’ll start with this one talking about the new Entity Framework changes and my hacks to use them my way.

Disclaimer:  I got the base concept of how I do things from someone else, but for the life of me I can’t find the blog post I found months ago that outlines this.  I’ll come back and update it once I find it, I’m pretty sure it was posted right before the EF 4.0 was released if that helps anyone find it.

Ok, so, back to my way.

When using the new Entity Framework features, I almost always use the new Self Tracking Entities by using the Context Menu in the Edmx designer and selecting “Add Code Generation Item”.

image

One of the major reasons I love the new STE templates is the separation of my domain objects from the data context.  So let me backup by saying I almost always setup my project structure like so:

image

Now, once we’ve added the STE project we’ll have 3 files created.   The Edmx, the Name.Context.tt, and the Name.tt.   The Name.Context file holds the ObjectContext class which manages the connections, adding, editing, etc.   The Name.tt file handles the generation of all your domain objects.

So the first thing I’ll do after doing that, is add a DomainObjects class library project.  Create my generated folder (because the contents is generated) and add the Name.tt file “As a Link” I also select the original file and empty the “Custom Tool” property.

This causes all of my domain objects to be created in a separate project. (Yay!)  Once that’s done, there are a few tweaks I still need to make.  Because my files are in the generated folder, they’re namespace will also end with “Generated”.  I can’t have that, so I edit the property “Custom Tool Namespace” on each file so that it makes sense.

So in the end, we’re left with a project structure somewhat like the screenshot above.  Take note of the “Partials” folder.  that’s where I stick my partial classes for my domain objects, this holds customized metadata like the following for the Agent class.

   1: using System.ComponentModel;
   2: using System.ComponentModel.DataAnnotations;
   3:  
   4: namespace Pax.DomainObjects
   5: {
   6:     [MetadataType(typeof(IAgentMetaData))]
   7:     public partial class Agent
   8:     {
   9:     }
  10:  
  11:     public interface IAgentMetaData
  12:     {
  13:         [StringLength(50)]
  14:         [Required]
  15:         [DisplayName("First Name")]
  16:         string FirstName { get; set; }
  17:  
  18:         [StringLength(50)]
  19:         [Required]
  20:         [DisplayName("Last Name")]
  21:         string LastName { get; set; }
  22:  
  23:         [DataType(DataType.PhoneNumber)]
  24:         string BusinessNumber { get; set; }
  25:  
  26:         [DataType(DataType.PhoneNumber)]
  27:         string HomeNumber { get; set; }
  28:  
  29:         [DataType(DataType.PhoneNumber)]
  30:         string FaxNumber { get; set; }
  31:  
  32:         [DataType(DataType.PhoneNumber)]
  33:         string MobileNumber { get; set; }
  34:  
  35:         [DataType(DataType.EmailAddress)]
  36:         string EmailAddress { get; set; }
  37:  
  38:         [DataType(DataType.Url)]
  39:         string WebPage { get; set; }
  40:  
  41:         [DataType(DataType.MultilineText)]
  42:         string Notes { get; set; }
  43:     }
  44: }

 

At this point we’re all setup.  But wait, what if we want to customize the code generated by the T4 template?  Well go right ahead, I do it all the time.  But one thing that has always bugged me in the past, is I need to go and modify this every time I start a new project.  Well not any more! Introducing the “Common” folder.

What I did was took a generic project and did the steps above.  I then took the T4 templates and modified them the way I like them, for example, auto adding the StringLength property, auto adding the Using statement for my DomainObjects class etc.  Next I wrapped them so that I could call them as a function so that I could include them, rather than execute them directly.   Then I put them in the Common Folder like so:

image

I’m not sure if I need to include the EF.Utility.CSv2.ttinclude or not, but I put it there anyway.  So now, my Name.Content.tt and my Name.tt files simply include them.  The code for each looks like this:

Pax.Context.tt

   1: <#@ include file="Common/Context.tt"#><#
   2: BeginCode(@"Pax.edmx");
   3: #>
   4:  
   5: <#+
   6: string GetCustomUsings()
   7: {
   8:     return "using Pax.DomainObjects;";
   9: }
  10: #>

 

Pax.tt

   1: <#@ include file="Common/DomainObjects.tt"#><#
   2: BeginCode(@"Pax.edmx");
   3: #>

 

There are two huge benefits to this.

1.  At work, I often use multiple Edmx’s for a project.  I’m not going to explain why, needless to say, if my T4 templates are setup like this, then any modifications I need to make to the main template, automagically get applied to every template that implements them.

2. When I create a new project, I can copy this setup into it, and I’m off and running with all of my normal customizations, without having to dig through the created template to make the changes.


I’m not going to post the entire contents of my Context/DomainObjects templates, but I have them attached for your use.  Keep in mind, they’re not changed drastically, I mostly just made some tweaks, and then wrapped the primary code generation portion in a method called BeginCode that accepts an input file.  I also added a virtual method so you can auto include using statements.   That’s about it.

Hope you find this useful!

Attachments: Custom.T4.SelfTrackingEntities.zip

Print | posted on Sunday, September 05, 2010 12:53 PM | Filed Under [ entity-framework t4 ]

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 2 and 8 and type the answer here:

Powered by:
Powered By Subtext Powered By ASP.NET