http://www.codeproject.com/useritems/SCTemplates.asp |
OverviewAs described in the part one of this series, SmartCode uses a template engine to transform some kind of "model" into compilable code. In this second part of the series, I will teach how to build a template to generate stored procedures, and finally how to use the new Open Source Implementation of a CodeSmith-Style Code Generation Engine (TahoGen). Also you can jump to the third part of the serie, to play with NHibernate and Smart Code. Now Smart Code offer a new set of Templates to generate code for NHibernate + ASPX, the code is based on the NHibernate Best Practices with ASP.NET article. More info about these templates in the article named NHibernate Templates for Smart Code Generator. IntroductionMost of the real-world code generators, both commercial and open source releases, use script based templates and template engines to transform data from a format to another. In the .NET Framework, usually code generators templates are written in ASP.NET style <% %> syntax. And using .NET class, associated to an specific data model to transform this input, in an formatted output, specified by the template SmartCode is a very flexible, powerful and open source code generator. The most new features of SmartCode is an alternative to tipical ASP.NET code styles. The Templates are created in C# or VB.NET (or theoretically in any .NET language in which a dynamic-link library (DLL) may be created) and compiled as dlls. This is a very powerful paradigm, to allow you using Visual Studio to create, compile and debug the templates. Template LibrariesCode-generation templates are organized in dlls. For a DLL to be considered an SmartCode library, it has to expose a certain interface, which will be specified in detail in the next section. To facilitate the creation of this interface, the SmartCode source package comes with base classes that already declare the necessary properties and methods, and which may be used to create libraries and templates by the use of class inheritance.SmartCode in ActionIn SmartCode Each Template look like this (in VB.NET):
Collapse
Imports System Imports SmartCode.Template Public Class Sample3 Inherits TemplateBase Public Sub New() MyBase.Name = "Sample3" MyBase.CreateOutputFile = True MyBase.Description = "This template demonstrates " & _ "using static and dynamic contents." MyBase.OutputFolder = "Samples\Sample3" MyBase.IsProjectTemplate = False End Sub Public Overloads Overrides Function OutputFileName() As String Return Table.Code + "_Sample3.txt" End Function Public Overloads Overrides Sub ProduceCode() WriteLine("Table: " + Table.Name) For Each column As SmartCode.Model.Column In Table.AllColumns WriteLine("Column: {0}: {1}", column.Name, column.NetDataType) Next End Sub End Class The code listed is a sample template that will write out all of the column names from any table.
Collapse
Table: : Employees EmployeeID : System.Int32 LastName : System.String FirstName : System.String Title : System.String TitleOfCourtesy : System.String BirthDate : System.DateTime HireDate : System.DateTime Address : System.String City : System.String Region : System.String PostalCode : System.String Country : System.String HomePhone : System.String Extension : System.String Photo : System.Byte[] Notes : System.String ReportsTo : System.Int32 PhotoPath : System.String Getting StartedAs described SmartCode uses a template engine to transform some kind of model, the SmartCode Model, into output code, given the output specified by a template Internal Core ModelThe internal core model is the core of SmartCode generator architecture. This contains a set of classes that make it easily manipulate the public methods and properties, to generate outputs. In order to add the SmartCode engine in the game, you class must inherits from a class System.Collections.ArrayList Run(SmartCode.Model.Domain domain, SmartCode.Model.NamedObject entity) Passing the context domain and entity objects, defined by each selected object in the Setting Code Generation Dialog.
The Now that it's clear how that SmartCode works, we can concentrate on the implementation of the Templates interfaceA DLL file is considered an SmartCode Template library, whenever it directly or not inherits from a class
TemplateBase is an abstract class you must Implement the next Methods
When you are done with the code compile, and the dll to be available to SmartCode Studio. Writing Our TemplateNow that it's clear how that Templates libraries structure, we can begin writing our template. A good idea to start with our template is build how the output we like. Here is an example All code is available in the source package of SmartCode
Collapse
To Build the list of primary key parameters, we can get these values from string inputParameters = String.Empty;
foreach (Column column in Table.PrimaryKeyColumns())
{
inputParameters += " " + Common.GetSqlParameterLine(column);
}
inputParameters = Common.Substring(inputParameters, Environment.NewLine.Length + 1);
WriteLine(" ({0} {1} {0})", Environment.NewLine, inputParameters); Where GetSqlParameterLine is an rutine defined in Common class that returns the type of the field as a T-SQL type, like varchar(length-of-field). There is a method worth noting, called Now we need build the body of the Store procedure, we can split up into 4 parts:
foreach (Column columm in Table.AllColumns())
{
selectStm.AppendFormat(" [{0}].[{1}] as {2},{3}", Table.Name, columm.Name, columm.Code, Environment.NewLine);
}
The list of values (LOV) an very nice feature added to SmartCode Model, that allow you lookup for values in parent tables, as shows the next image: int i = 0;
foreach (Reference reference in Table.InReferences){
foreach (ReferenceJoin join in reference.Joins){
//Searchs for LOV
foreach (Column lovColumn in join.LOV){
if (lovColumn.Name != join.ParentColumn.Name){
selectStm.AppendFormat(" [T{0}].[{1}] as {2}_{3},{4}",
i, lovColumn.Name, join.ChildColumn.Code,
lovColumn.Code, Environment.NewLine);
}
}
}
i += 1;
}
//Remove the '\n,'
selectStm = new StringBuilder(Common.Substring(selectStm.ToString(), Environment.NewLine.Length + 1));
//Write the code
WriteLine(selectStm.ToString());
The From Part, you can access to external 'InReferences' to build a more complex FROM.
Collapse
i = 0;
string alignment = "";
foreach (Reference reference in Table.InReferences)
{
if (reference.Alignment == Reference.AlignmentType.Inner)
alignment = " INNER JOIN ";
else if (reference.Alignment == Reference.AlignmentType.Left)
alignment = " LEFT OUTER JOIN ";
else if (reference.Alignment == Reference.AlignmentType.Right)
alignment = " RIGHT OUTER JOIN ";
selectStm.AppendFormat(" {0} {1} AS T{2} ",alignment +
Environment.NewLine , reference.ParentTable.Name, i);
string onJoin = "";
foreach (ReferenceJoin join in reference.Joins)
{
onJoin += String.Format(" ON T{0}.[{1}] = [{2}].[{3}] AND", i,
join.ParentColumn.Name, Table.Name,
join.ChildColumn.Name);
onJoin += Environment.NewLine;
}
//Remove the last AND
onJoin = Common.Substring(onJoin, Environment.NewLine.Length + 3);
selectStm.Append(onJoin);
i += 1;
}
And the Where Part string keyCondition = String.Empty;
foreach (Column column in Table.PrimaryKeyColumns())
{
keyCondition += String.Format(" [{0}] = @{1} AND {2}", column.Name, column.Code, Environment.NewLine);
}
keyCondition = Common.Substring(keyCondition, (Environment.NewLine.Length + 5));
WriteLine(" WHERE {0}({0} {1} {0})", Environment.NewLine, keyCondition);
Project Level TemplatesIn the last sections we have learn to generate code running templates assigned to entities, But else in the practices usually we have to generate code for all objects contained in the domain e.g. the list of all tables in the database; a simple way to make this easier is create a new the template with next code: foreach (Table table in Domain.ConnectionInfo.Tables)
{
WriteLine(table.Name);
}
And assign the template to any, and only one, entity and run it. With SmartCode we have the option to assign a template to project level, to run only one time, each time that we run the code generation, we can found this template in the second tab called "Project Templates", in the main "Setting Code Generation" dialog, as shows the next figure: To be available the template in this tab we need to assign true to the property
Collapse
public class AllStoreProcedures : TemplateBase
{
// Constructor.
public AllStoreProcedures()
{
this.IsProjectTemplate = true;
this.createFile = true;
this.description = "Generates all stored procedure for all entities in the domain";
this.name = "AllStoreProcedures";
this.outputFolder = @"Stored Procedures\AllStoreProcedures";
}
public override string OutputFileName()
{
return Domain.Name + "_AllSps.sql";
}
public override void ProduceCode()
{
foreach (Table table in Domain.ConnectionInfo.Tables)
{
if (table.IsTable && table.PrimaryKeyColumns().Count > 0)
{
RunTemplate(new DeleteRowByPrimaryKey(), table);
RunTemplate(new Insert(), table);
RunTemplate(new Update(), table);
}
}
}
private void RunTemplate(TemplateBase template, Table table)
{
System.Collections.ArrayList results = template.Run(Domain, table);
//The code prop, containts the output string. append the results,
//look for Run
base.code.Append(results[0]);
}
}
CodeSmith CompatibilityIs an extension of SmartCode based in TahoGen, an Open Source Implementation of a CodeSmith-Style Code Generation Engine, this implementation can parse any CodeSmith Template, giving a starting point for thier migration to SmartCode from CodeSmith. Please refer to NHibernate samples in the TaHoGen Directory of source package. In order to maintain the basic structure for Templates and support asp like style the next extensions has been implemented.
The differences between the template language provided by TahoGen and CodeSmith are minimal. Let see the next header <%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Generates a C# class for use with NHibernate."%> <%@ Property Name="SourceTable" Type="SmartCode.Model.Mapping.CS.TableSchema" Category="Context" Description="Table that the mapping file" %> <%@ Property Name="Namespace" Type="System.String" Default="MyNamespace.Data" Category="Object" Description="The class namespace %> The template reads 2 properties SourceTable of the type SmartCode.Model.Mapping.CS.TableSchema provided by SmartCode.Model.Mapping.dll and Namespace of type System.String. The values of SourceTable is provided for the next code of the NHibernateClass template: public override PropertyTable GetCustomPropertyTable()
{
PropertyTable properties = new PropertyTable();
SmartCode.Model.Mapping.CS.CSMap csMap = new SmartCode.Model.Mapping.CS.CSMap(Domain);
csMap.RunMapToCS();
SmartCode.Model.Mapping.CS.DatabaseSchema databaseSchema = csMap.DatabaseSchema;
properties["SourceTable"] = csMap.GetTableByName(Table.Name);
return properties;
}
Has you been see the code set the SourceTable of the template, after Map the SmartCode.Model objects to SmartCode.Model.Mapping.CS objects, to be compatible with the CodeSmith objects model. The Core Template LibrariesThe SmartCode package comes with a Beta core sets of template libraries for generating code in C#, that use stored procedures to access and modify data.
ConclusionIn this article we have view the huge benefits of using templates to avoid repetitive coding tasks. SmartCode Model provide the Object Model, SmartCode Studio provide the IDE to customize your Model and you.... provide the Imagination, Creativity and Inspiration. About Danilo Mendez |
转载于:https://www.cnblogs.com/jerryzhao/archive/2007/08/27/871667.html