Using T4 to automatically generate your entities

*** This is a repost of a previous post because of moving to a new blog engine in which some formatting was lost ***

Today I discovered something very interesting, namely how to automatically generate my entity classes (classes that also implement the INotifyPropertyChanged and IDataErrorInfo interfaces) using T4.

T4 is a text generation language built into Visual Studio 2005 and later, normally intended for DSL code generation. But we can also use it for generating any code we would like. I for one, I would like automatic properties to automatically implement INotifyPropertyChanged if the interface is on the class, but of course, life doesn’t work that way *sigh*. The real problem is that for each property you have, part of the implementation needs to raise an event using the property name. When you change the name of the property you also have to change this string, which is error prone…

Instead we can generate code using T4, and to be honest, it isn’t that difficult to use. First of all, go to tangible to download their free T4 intelli-sense tool.

Next add to your project a new text file, naming it Entity.tt (the extension is important!). Now add this content:

<#@ template language="C#" #>
<#@ output extension="cs" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
// ---------------------------------
// U2U Sample, use at your own risk!
//        http://www.u2u.be
// ---------------------------------

using System;
using System.ComponentModel;
using System.Collections.Generic;

namespace <#= this.Namespace #> 
{  
  public partial class <#= this.ClassName #> 
    : INotifyPropertyChanged
    , IDataErrorInfo  
  {
    #region Private fields
    <# for (int idx = 0; idx < this.properties.GetLength(0); idx++) { #>    
    private <#= this.properties[idx,0] #> _<#= this.properties[idx,1].ToLower() #>;<# }#>   
    
    #endregion
    
    #region Properties
    <# for (int idx = 0; idx < this.properties.GetLength(0); idx++) { #>    
    public <#= this.properties[idx,0] #> <#= this.properties[idx,1] #>
    {        
      get
      {            
        return _<#= this.properties[idx,1].ToLower() #>;        
      }        
      set        
      {            
        _<#= this.properties[idx,1].ToLower() #> = value;
        OnPropertyChanged("<#= this.properties[idx,1]#>");        
      }   
    }
    <#   }   #>      
    #endregion
    
    #region INotifyPropertyChanged Members   
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged(string propertyName)   
    {       
      if (PropertyChanged != null)           
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));   
    }   
    
    #endregion
    
    #region IDataErrorInfo Members
    
    private string _error = null;
    
    public string Error {
      get
      { 
        return _error; 
      }
      set 
      {
        _error = value;
      }
    }
    
    private Dictionary<string,string> _columnErrors =
      new Dictionary<string,string>();
      
    public string this[string columnName]
    {
      get
      {
        if( _columnErrors != null && _columnErrors.ContainsKey(columnName))
          return _columnErrors[columnName];
        else
          return null;
      }
      set
      {
        if( value != null ) // Insert error
        {
          if( _columnErrors == null )
          {
            _columnErrors = new Dictionary<string,string>();
          }
          _columnErrors[columnName] = value;
        }
        else // Clear error
        {
          _columnErrors.Remove(columnName);
          if (_columnErrors.Count == 0)
          {
            _columnErrors = null;
          }
        }
        // Notify validation that something has changed
        OnPropertyChanged( columnName );
      }
    }
    #endregion
  }
}

<#+    
  string Namespace = "Demo";    
  string ClassName = "DemoClass";    
  string[,] properties = {        
    {"int", "Property1"},        
    {"string", "Property2"}
  };               
#>

Building your project will generate a little DemoClass with these two properties. But that is of course not what you want; so add another file Category.tt:

<#    
  this.Namespace = "U2U.Samples";    
  this.ClassName = "Category";    
  this.properties = new string[,]
  {        
    {"int"   , "CategoryID"}
  , {"string", "CategoryName"}      
  , {"string", "Description"}      
  , {"byte[]", "Picture"}
  }; 
#>

<#@ include file="Entity.tt" #>

Building will now automatically generate a Category.cs file with code like this:

// ---------------------------------
// U2U Sample, use at your own risk!
//        http://www.u2u.be
// ---------------------------------

using System;
using System.ComponentModel;
using System.Collections.Generic;

namespace U2U.Samples
{
  public partial class Category
    : INotifyPropertyChanged
    , IDataErrorInfo
  {
    #region Private fields

    private int _categoryid;
    private string _categoryname;
    private string _description;
    private byte[] _picture;

    #endregion

    #region Properties

    public int CategoryID
    {
      get
      {
        return _categoryid;
      }
      set
      {
        _categoryid = value;
        OnPropertyChanged("CategoryID");
      }
    }

    public string CategoryName
    {
      get
      {
        return _categoryname;
      }
      set
      {
        _categoryname = value;
        OnPropertyChanged("CategoryName");
      }
    }

    public string Description
    {
      get
      {
        return _description;
      }
      set
      {
        _description = value;
        OnPropertyChanged("Description");
      }
    }

    public byte[] Picture
    {
      get
      {
        return _picture;
      }
      set
      {
        _picture = value;
        OnPropertyChanged("Picture");
      }
    }

    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion

    #region IDataErrorInfo Members

    private string _error = null;

    public string Error
    {
      get
      {
        return _error;
      }
      set
      {
        _error = value;
      }
    }

    private Dictionary<string, string> _columnErrors =
      new Dictionary<string, string>();

    public string this[string columnName]
    {
      get
      {
        if (_columnErrors != null && _columnErrors.ContainsKey(columnName))
          return _columnErrors[columnName];
        else
          return null;
      }
      set
      {
        if (value != null) // Insert error
        {
          if (_columnErrors == null)
          {
            _columnErrors = new Dictionary<string, string>();
          }
          _columnErrors[columnName] = value;
        }
        else // Clear error
        {
          _columnErrors.Remove(columnName);
          if (_columnErrors.Count == 0)
          {
            _columnErrors = null;
          }
        }
        // Notify validation that something has changed
        OnPropertyChanged(columnName);
      }
    }
    #endregion
  }
}

So to change/add/remove a property, we edit the Category.tt file and all the rest is done automatically.

Now for some feedback, what is your way of implementing IDataErrorInfo?

Comments (10) -

December 20. 2009 05:15 PM

www.playcasinobonuses.com

The beauty of these blogging engines and CMS platforms is the lack of limitations and ease of manipulation that allows developers to implement rich content and 'skin' the site in such a way that with very little effort one would never notice what it is making the site tick all without limiting content and effectiveness.

www.playcasinobonuses.com

December 22. 2009 07:58 AM

short sale listings

That is some inspirational stuff. Never knew that opinions could be this varied. Thanks for all the enthusiasm to offer such helpful information here.

short sale listings

December 22. 2009 07:20 PM

payday loans

Hmmm interesting stuff

payday loans

December 26. 2009 01:38 PM

portland bankruptcy lawyer

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post

portland bankruptcy lawyer

December 26. 2009 05:24 PM

raw dog food

Resources like the one you mentioned here will be very useful to me! I will post a link to this page on my blog. I am sure my visitors will find that very useful.

raw dog food

December 27. 2009 07:13 PM

l&#229;n uten sikkerhet

Have you ever considered adding more videos to your blog posts to keep the readers more entertained? I mean I just read through the entire article of yours and it was quite good but since I'm more of a visual learner,I found that to be more helpful well let me know how it turns out! I love what you guys are always up too. Such clever work and reporting! Keep up the great works guys I've added you guys to my blogroll. This is a great article thanks for sharing this informative information.. I will visit your blog regularly for some latest post.

lån uten sikkerhet

December 31. 2009 03:24 PM

no loss robot

There are certainly a lot of details like that to take into consideration. That is a great point to bring up. I offer the thoughts above as general inspiration but clearly there are questions like the one you bring up where the most important thing will be working in honest good faith. I don?t know if best practices have emerged around things like that, but I am sure that your job is clearly identified as a fair game.

no loss robot

January 3. 2010 03:49 PM

Refurbished Garmin

I admire what you have done here. I like the part where you say you are doing this to give back but I would assume by all the comments that this is working for you as well.

Refurbished Garmin

January 3. 2010 05:27 PM

Las Vegas Photographer

Howdy, i read your blog occasionally and i own a similar one and i was just wondering if you get a lot of spam comments? If so how do you prevent it, any plugin or anything you can advise? I get so much lately it's driving me mad so any assistance is very much appreciated.

Las Vegas Photographer

January 22. 2010 09:04 PM

bad credit payday loans

Work is not man's punishment. It is his reward and his strength and his pleasure.

bad credit payday loans

January 25. 2010 02:05 PM

payday loans

He who angers you conquers you.

payday loans

January 25. 2010 02:05 PM

bad credit loans

Success is simple. Do what's right, the right way, at the right time.

bad credit loans

February 9. 2010 09:08 AM

colon cleanse

Choose a job you love, and you will never have to work a day in your life.

colon cleanse

February 26. 2010 06:58 AM

stock loan

Just wanted to give you a shout from the valley of the sun, great information. Much appreciated.

stock loan

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

Download the U2U brochure

Download Brochure

Receive the U2U Newsletter. Submit your email address:
 
 


 


Search

rss  RSS

Recent posts

None

Archive