Posts tagged with codesmith

CodeSmith template to generate LINQ To SQL Data Context

If you are interested in what LINQ to SQL generates and don’t have Orcas installed or available right now but use CodeSmith try the following template to generate very similar code.

The primary difference is that this writes out the System types rather than the C# aliases (e.g. System.Int32 instead of int) but that could easily be changed but is binary compatible and otherwise almost identical to the source.

Download LINQ to SQL template (CodeSmith) (4 KB)

<%@ CodeTemplate Src="LinqFunctions.cs" Inherits="LinqFunctions" Language="C#" TargetLanguage="C#"
  Description="Generates a data context and entities for given tables." %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Data" %>
<%@ Property Name="DataContextClassName" Type="System.String" Category="Naming" Optional="True"Description="Name of the data context class to generate." %>
<%@ Property Name="Namespace" Type="System.String" Category="Naming" Optional="True" Description="Namespace for the data context class to generate." %>
<%@ Property Name="SourceTables" Type="SchemaExplorer.TableSchemaCollection" Category="Connection"Description="Tables to be mapped." %>
<%SchemaExplorer.DatabaseSchema database = SourceTables[0].Database;
string className = (String.IsNullOrEmpty(DataContextClassName)) ? DatabaseName(database) + "DataContext" : DataContextClassName;
Dictionary<TableSchema, List<TableKeySchema>> reverseForeignKeys = new Dictionary<TableSchema, List<TableKeySchema>>();
foreach(TableSchema table in SourceTables) {
    foreach(TableKeySchema keySchema in table.ForeignKeys) {
        if (reverseForeignKeys.ContainsKey(keySchema.PrimaryKeyTable)) {
            reverseForeignKeys[keySchema.PrimaryKeyTable].Add(keySchema);
        }
        else {
            List<TableKeySchema> keySchemas = new List<TableKeySchema>();
            keySchemas.Add(keySchema);
            reverseForeignKeys.Add(keySchema.PrimaryKeyTable, keySchemas);
        }
    }
}%>//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     CodeSmith template DeLINQuent.cst v0.1
//     Generated by <%=CurrentUserName()%> at <%=DateTime.Now%>
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace <%=Namespace%>{
    public partial class <%=className%> : global::System.Data.Linq.DataContext
    {
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public <%=className%>(string connection) :
                base(connection)
        {
        }

        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public ProjectDataContext(global::System.Data.IDbConnection connection) :
                base(connection) {
        }
<%    foreach(TableSchema table in SourceTables) {
        string entityName = EntityName(table);
        string propertyName = TableName(table);%>
        public global::System.Data.Linq.Table<<%=entityName%>> <%=propertyName%> {
            get {
                return this.GetTable<<%=entityName%>>();
            }
        }
<%     } %>
    }<%    foreach(TableSchema table in SourceTables) {
        string entityName = EntityName(table);%>
    [global::System.Data.Linq.Table(Name="<%=table.FullName%>")]
    public partial class <%=entityName%> :global::System.Data.Linq.INotifyPropertyChanging,global::System.ComponentModel.INotifyPropertyChanged
    {
<%    foreach(ColumnSchema column in table.Columns) { %>
        private <%=NullableSystemType(column)%> _<%=PropertyName(column)%>;
<%    }
      if (table.ForeignKeys.Count > 0) { %>
<%        foreach(TableKeySchema keySchema in table.ForeignKeys) {
            string foreignEntityName = EntityName(keySchema.PrimaryKeyTable);%>
        private global::System.Data.Linq.EntitySet<<%=foreignEntityName%>> _<%=foreignEntityName%>;<%
          }
      }
      if (reverseForeignKeys.ContainsKey(table)) { %>
<%        foreach(TableKeySchema keySchema in reverseForeignKeys[table]) {
            string propertyName = TableName(keySchema.ForeignKeyTable);%>
        private global::System.Data.Linq.EntityRet<<%=EntityName(keySchema.ForeignKeyTable)%>> _<%=propertyName%>;
<%        }
      } %>
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public <%=entityName%>() {
        }
<%    foreach(ColumnSchema column in table.Columns) {
        string propertyName = PropertyName(column);%>
        [global::System.Data.Linq.Column(Storage="_<%=propertyName%>", Name="<%=column.Name%>", DBType="<%=AttributeColumnDbType(column)%>"<%
            if (column.IsPrimaryKeyMember) { %>, IsPrimaryKey=true<% }
            if (!column.AllowDBNull) { %>, CanBeNull=false<% } %>)]
        public <%=NullableSystemType(column)%> <%=propertyName%> {
            get {
                return this._<%=propertyName%>;
            }
            set {
                if (this._<%=propertyName%> != value) {
                    this.OnPropertyChanging("<%=propertyName%>");
                    this._<%=propertyName%> = value;
                    this.OnPropertyChanged("<%=propertyName%>");
                }
            }
        }

<%    } %>
<%    foreach(TableKeySchema keySchema in table.ForeignKeys) {
        string propertyName = EntityName(keySchema.PrimaryKeyTable);
        string tableName = TableName(keySchema.PrimaryKeyTable);%>
        [global::System.Data.Linq.Association(Name="<%=keySchema.Name%>",
            Storage="_<%=propertyName%>", OtherKey="<%=AttributeColumnList(keySchema.ForeignKeyMemberColumns)%>",
            ThisKey="<%=AttributeColumnList(keySchema.PrimaryKeyMemberColumns)%>", IsForeignKey=true)]
        public <%=propertyName%> <%=propertyName%> {
            get {
                return this._<%=propertyName%>.Entity;
            }
            set {
                if (this._<%=propertyName%>.Entity != value) {
                    this.OnPropertyChanging("<%=propertyName%>");
                    if ((this._<%=propertyName%>.Entity != null)) {
                        <%=propertyName%> temp = this._<%=propertyName%>.Entity;
                        this._<%=propertyName%>.Entity = null;
                        temp.<%=TableName(table)%>.Remove(this);
                    }
                    this._<%=propertyName%>.Entity = value;
                    if ((value != null)) {
                        value.<%=TableName(table)%>.Add(this);
                    }
                    this.OnPropertyChanged("<%=propertyName%>");
                }
            }
        }
<%    } %>
<%    if (reverseForeignKeys.ContainsKey(table)) {
        foreach(TableKeySchema keySchema in reverseForeignKeys[table]) {
            string propertyName = TableName(keySchema.ForeignKeyTable);%>
        [global::System.Data.Linq.Association(Name="<%=keySchema.Name%>",
            Storage="_<%=propertyName%>", OtherKey="<%=AttributeColumnList(keySchema.PrimaryKeyMemberColumns)%>",
            ThisKey="<%=AttributeColumnList(keySchema.ForeignKeyMemberColumns)%>")]
        public IEnumerable<<%=EntityName(keySchema.ForeignKeyTable)%>> <%=propertyName%> {
            get {
                return this._<%=propertyName%>;
            }
        }

<%             }
        } %>
        public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanging;
        public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        protected void OnPropertyChanging(string propertyName) {
            if (this.PropertyChanging != null)
                this.PropertyChanging(this, new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        protected void OnPropertyChanged(string propertyName) {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
<%     } %>
}

[)amien

My 2006 development tools

Christopher Bennage wrote about his development tool set-up and encouraged others to do the same so here’s my current set-up.

Daily tools

  • Visual Studio 2005 – IDE of preference despite it’s sluggish behavior
  • SQL Server 2005 Management Studio – Took getting used to but it’s an improvement on 2000’s Enterprise Manager
  • AnkhSVN – Subversion support inside Visual Studio 2005
  • .NET Reflector – Searching .NET API or to find out what it’s doing
  • Web Application Projects – Stop using VS’s web sites and start using web applications!
  • Web Deployment Projects – Deploy to dev, test or live servers as easily as building a project

Not quite daily

  • CodeSmith – Need to get to grips with v4 to build our whole database layer in one hit
  • Trac – Bug tracking, milestones & wiki with integrated support for Subversion
  • TortoiseSVN – Check-in/out of non-project items (e.g. art assets)
  • Web Developer Extension – Trying CSS changes on-the-fly, validating pages etc. from Firefox
  • Firebug – Examining pages, the page DOM etc. from Firefox
  • KDiff – Excellent 3-way diff tool that works great with AnkhSVN
  • Subtext – Blogging system running here

On occasion

  • Visual C# Express and XNA – Messing with 3D graphics, controllers and pixel shaders
  • Ogre – Steve’s object-oriented 3D engine
  • Xcode and Cocoa – Still quite alien with it’s message-based calling mechanism but obviously powerful

Keeping an eye on

  • Eclipse – IDE for developing Java (C++ and C# support in various stages too)
  • Ruby on Rails – Interesting RAD approach to web development – Apple also supporting on Mac OS X 10.5
  • Sandcastle – Microsoft’s documentation tool that already seems to have had an impact on NDoc
  • SubSonic – Build-provider that generates an ORM on the fly and provides automatic developer-only db editing pages

Not used lately, still installed

  • Delphi 5/6 – Borland’s great RAD tool for non-.NET development, later versions support .NET too
  • JBuilder – Java development although I’d probably move to Eclipse
  • Visual Studio 2003 – Still required for the odd .NET 1.1 application/testing

[)amien

Choose your ORM: Runtime, code generation or build provider?

Selecting the right object-relational mapper is a tricky decision with many factors to weigh up.

One of the basic decisions is whether to go with a dynamic run-time (“black-box”) or a code generator.

I’m not a fan of the run-time approach – the discovery at run-time negatively impacts performance as it often uses reflection (or failing that post-compilation byte code modification) whilst robbing you of compile-time checking, IntelliSense support against your database objects, deployment and potentially licensing issues. In effect, it’s not that much better than a typed dataset.

Code generation provides for a much finer granularity letting you tweak the templates for the performance and features you need whilst also providing full compile-time checking and IntelliSense support.

Tools such as CodeSmith (my personal favorite), MyGeneration (free) do a good job of letting you write these templates and create the necessary ORM code but require being re-run every time you change the schema. During the starting phases of a project this could be quite often and goes against the whole concept of RAD.

So step in SubSonic and it’s build provider approach.

The idea here is that you modify your .config file to include the SubSonic build provider and it’s connection string, drop a simple text file in that lists which tables to work with and you’re done.

SubSonic now goes off to your database via the connection and generates all the code for tables you need and it’s magically there to be used like any other classes. Check out the demo to see just how easy it is.

SubSonic supports a large number of databases, has support for Enterprise Library, is open source and also provides simple “scaffold” pages that let you throw a basic web add/edit/update/delete table maintenance page by just throwing a table name attribute onto an empty page’s form element.

The only downside at this point is that it uses the ActiveRecord pattern for the ORM. If I manage to get some time to spend with it and can knock up a Domain Object + Data Mapper version I’ll let you know.

[)amien