This article will introduce the fundamentals of SourceMason code templates by dissecting a very basic business object template. The template only generates properties for the business object, it does not include any logic/output for loading or saving etc.

SchemaExplorer is an addon for SourceMason (included in the install) that allows you to read the schema for any type of database. In this example I will be using Sql Server 2005 and the AdventureWorks sample database.
Below is the SchemaExplorer interface and table classes. View and Command classes are not displayed in the diagram below.
A code template consists of three sections, a header section, script section and template body or markup section.
Template directives have the format of: <%@ some directive definition %>
The format is:
<%@ CodeTemplate Language="" TargetLanguage="" Src="" Inherits="" Description="" %>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="This template creates a basic business object." %>
The format is:
<%@ Property Name="" Type="" Default="" Optional="False" Category="" Description="" Editor="" EditorBase="" Serializer="" %>
<%@ Property Name="SourceTable" Type="EquatorIT.SchemaExplorer.TableSchema" Description="Table that should be read." %>
The format is: <%@ Using Namespace="" %>
<%@ Using Namespace="EquatorIT.SchemaExplorer" %>
The format is: <%@ Assembly Name="" %>
The Assembly directive allows assembly references to be added to your template. It the equivalent of using Add Reference in a C# or VB.NET project.<%@ Assembly Name="EquatorIT.SchemaExplorer" %>
The format is: <%@ Register Name="" Template="" %>
The Register directive allows other templates to be used within the template. These templates become sub-templates of the template.
The format is: <%@ Include FileName="" %>
The script section has the following format:
<script runat="template">
</script>
The template body or markup section is where the template output is defined. It contains a combination of static output and markup. Static output is text that will be rendered unchanged to the template output. Template markup is used in addition to static output to create template output.
There are three types of markup elements, inline expression, inline code, and comment elements.Inline expressions have the format:
<%= SomeExpression%>
where SomeExpression is an expression
<% foreach(TableColumnSchema column in SourceTable.Columns)
{ %>
Database Type - <%= column.DbType %>
.Net Type - <%= column.Type %>
<%} %>
The Inline Code element allows programatic control of template output. The code used is of the type specified in the CodeTemplate directive Language attribute.
Comments may span multiple lines and will not form part of the code template's output. The SourceMason Engine will ignore the content inside the comment element.
Example:<%-- TemplateName: BusinessObject.smt Author: Brett Watt Description: Generate business object class from database table schema --%>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="" %>
<%@ Property Name="SourceTable" Type="EquatorIT.SchemaExplorer.TableSchema" Description="Table that should be read to create the business object." %>
<%@ Property Name="Namespace" Type="string" Default="" Optional="False" Category="" Description="Namespace for the business object" Editor="" EditorBase="" Serializer="" %>
<script runat="template">
private string GetMemberVariableInit(TableColumnSchema column)
{
switch (column.Type.ToString().ToUpper())
{
case "SYSTEM.STRING":
return " = string.Empty";
case "SYSTEM.GUID":
return " = Guid.Empty";
break;
}
return string.Empty;
}
</script>
using System;
using System.ComponentModel;
using System.Collections;
namespace <%= Namespace %>
{
[Serializable]
public class <%= EquatorIT.Common.StringUtils.ToPascalCase(SourceTable.Name) %>
{
<%foreach(TableColumnSchema column in SourceTable.Columns) %>
<%{ %>
protected <%= EquatorIT.Common.TypeUtils.GetCSharpTypeFromDotNetType(column.Type.ToString()) %> _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %><%= GetMemberVariableInit(column)%>;
<%} %>
public <%= EquatorIT.Common.StringUtils.ToPascalCase(SourceTable.Name) %>()
{
}
#region Properties
<%foreach(TableColumnSchema column in SourceTable.Columns) %>
<%{ %>
public <%= EquatorIT.Common.TypeUtils.GetCSharpTypeFromDotNetType(column.Type.ToString()) %> <%= EquatorIT.Common.StringUtils.ToPascalCase(column.Name) %>
{
get { return _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %>; }
set { _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %> = value; }
}
<%} %>
#endregion
}
}
namespace <%= Namespace %>I use the template property Namespace in an inline expression element to output the namespace for the class.
public class <%= EquatorIT.Common.StringUtils.ToPascalCase(SourceTable.Name) %>I use a helper function to convert the SourceTable Name to pascal case and ouptut as the class name.
<%foreach(TableColumnSchema column in SourceTable.Columns) %>
<%{ %>
protected <%= EquatorIT.Common.TypeUtils.GetCSharpTypeFromDotNetType(column.Type.ToString()) %> _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %><%= GetMemberVariableInit(column)%>;
<%} %>
I use an inline code element to iterate through all the TableColumnSchema objects in SourceTable.Columns and create the corresponding member variables. I also use a helper function to create the initialisation expression for each member variable.
<%foreach(TableColumnSchema column in SourceTable.Columns) %>
<%{ %>
public <%= EquatorIT.Common.TypeUtils.GetCSharpTypeFromDotNetType(column.Type.ToString()) %> <%= EquatorIT.Common.StringUtils.ToPascalCase(column.Name) %>
{
get { return _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %>; }
set { _<%= EquatorIT.Common.StringUtils.ToCamelCase(column.Name) %> = value; }
}
<%} %>
I use an inline code element to iterate through all the TableColumnSchema objects in SourceTable.Columns and create the corresponding properties. I also get the CSharp type by using the GetCSharpTypeFromDotNetType helper function.
using System;
using System.ComponentModel;
using System.Collections;
namespace Example
{
[Serializable]
public class Address
{
protected int _addressID;
protected string _addressLine1 = string.Empty;
protected string _addressLine2 = string.Empty;
protected string _city = string.Empty;
protected int _stateProvinceID;
protected string _postalCode = string.Empty;
protected Guid _rowguid = Guid.Empty;
protected DateTime _modifiedDate;
public Address()
{
}
#region Properties
public int AddressID
{
get { return _addressID; }
set { _addressID = value; }
}
public string AddressLine1
{
get { return _addressLine1; }
set { _addressLine1 = value; }
}
public string AddressLine2
{
get { return _addressLine2; }
set { _addressLine2 = value; }
}
public string City
{
get { return _city; }
set { _city = value; }
}
public int StateProvinceID
{
get { return _stateProvinceID; }
set { _stateProvinceID = value; }
}
public string PostalCode
{
get { return _postalCode; }
set { _postalCode = value; }
}
public Guid Rowguid
{
get { return _rowguid; }
set { _rowguid = value; }
}
public DateTime ModifiedDate
{
get { return _modifiedDate; }
set { _modifiedDate = value; }
}
#endregion
}
}