工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

 开篇

平常开发时,由于冗余代码过多,程序员做重复的工作过多势必会影响开发效率。倘若对重复性代码简单的复制、粘贴,虽然也能节省时间,但也需仔细一步步替换,这无疑也是一件费力的事。这时我们急需代码生成工具,根据一套Template快速生成我们需要的代码。代码生成器原理简单,完全可以开发一套适合自己的代码生成器,一个最简单的代码生成器,有几点你需要关注下:

  1. 查询系统视图:INFORMATION_SCHEMA.TABLES、 INFORMATION_SCHEMA.COLUMNS  可以获得数据库中表、列的相关信息。
  2. 字符串的拼接:StringBuilder的使用,其AppendLine()自动换行。
  3. 将字符串写入文本文件:File.WriteAllText()
  4. 使用了部分类(partial)
  5. 使用可空类型:由于数据库中表中数据很有可能是NULL,可空类型使得数据从表中读取出来赋值给值类型更加兼容。

当然自己开发的代码生成器局限性很大,但对于小项目也是很好的选择。我也写过两篇代码生成器的拙文,仅供参考。

说起代码生成器,不得不说Code Smith,基于Template的编程,下面举例的NTier架构是很基础的,除了熟悉的三层架构,还生成了抽象工厂、缓存、单例、反射、存储过程等,当然这个Demo只是学习用,大家可以继续扩展,打造自己的铜墙铁壁。

Code Smith

CodeSmith 是一种语法类似于asp.net的基于模板的代码生成器,程序可以自定义模板,从而减少重复编码的劳动量,提高效率。Code Smith提供自定义Template,语法也不复杂,类似于asp.net的标识符号,<%%>、<%=%>、<script runat="template">...</script>

Code Smith API

工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

N层架构-实体类模板-Entity Template

  • 首先创建一个C# template,创建指令集,导入程序集和名称空间:
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 
  • 添加属性Property:
<%--DataSourse--%>

<%@ Property Name="CurrentTable" Type="SchemaExplorer.TableSchema" Default="" Optional="False" DeepLoad="True" Category="" Description="" OnChanged="" Editor="" EditorBase="" Serializer="" %>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>
  • 一个简单的实体类模板内容,可以这样写:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace <%=this.RootNamespace%>.Entity

{

    public class <%= CurrentTable.Name%>

    {

        <% foreach(ColumnSchema col in CurrentTable.Columns)

        {%>

            public <%=col.DataType%> <%=col.Name%> {get;set;}

        <%}%>

            

    }

}

 

当然生成实体类时,需要考虑可空类型,写好一个Template,以后爽歪歪:)。

N层架构-数据访问层接口模板,IDao Template

  • Script标签里可以自定义调用的方法,属性等。数据访问层接口大家肯定烂熟于心。
  • 常用的CRUD方法以及主表找子表,子表找主表。
  • Script里面的方法,你需要熟悉一下Code Smith的API,我在上面已经贴出了常用的API,供大家参考。
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>

<%@ Property Name="CurrentTable" Type="SchemaExplorer.TableSchema" DeepLoad="True" Optional="False"  %>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>



using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using <%=this.RootNamespace%>.Model;



namespace <%=this.RootNamespace%>.IDao

{

    public interface I<%= this.CurrentTable.Name %>Dao

    {

         int Add(Model.<%= this.CurrentTable.Name %> entity);

         int Update(Model.<%= this.CurrentTable.Name %> entity);

         int Delete(Model.<%= this.CurrentTable.Name %> entity); 

         List<Model.<%= this.CurrentTable.Name %>> LoadAllEntities();

         Model.<%= this.CurrentTable.Name %> LoadByPK(<%= PKArgsForTable()%>);

 

    

    #region 主表找子表

    

    <% foreach(TableKeySchema fk in this.CurrentTable.ForeignKeys)

    {

    %>

        List<Model.<%=this.CurrentTable.Name%>> Query_<%=this.CurrentTable.Name%>List_By<%=fk.Name%>(<%=this.FKArgsForTable(fk)%>);

    <%}%>

    #endregion

    }

}











<script runat="template">



    

    //方法:生成列的主键列构成的参数列表

    public string PKArgsForTable()

    {

        string args="";

        foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

        {

                args += string.Format("{0} {1},",pkCol.Column.DataType,pkCol.Column.Name);  

        }

                   

         return args.Substring(0,args.Length-1);

    }

    

    //主键在子表中的外键所包含的列的参数列表带数据类型

    public string FKArgsForTable(TableKeySchema key){

      

         string args=""; 

        foreach(MemberColumnSchema Col in key.ForeignKeyMemberColumns)

        {

                args += string.Format("{1} {0},",Col.Column.Name,Col.DataType);

        }

                   

         return args.Substring(0,args.Length-1);

        }

</script>



                        

        

        

  

N层架构-抽象工厂-AbstactFactory Template

<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>



<%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False"%>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace <%=this.RootNamespace%>.AbstractFactory

{

    public abstract class DaoFactory

    {

<% foreach(TableSchema table in this.SourceDatabase.Tables)

{

    %>

    

        public abstract IDao.I<% = table.Name %>Dao <% = table.Name %>SqlProviderDao

        {

            get;

        }

    

    <%

    }

    %>



    }

}

        

  

N层架构-DaoSqlFactory Template

<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>



<%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False"%>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace <%=this.RootNamespace%>.SqlProviderDao

{

    public class DaoSqlFactory : <%=this.RootNamespace%>.AbstractFactory.DaoFactory

    {

    

<% foreach(TableSchema table in this.SourceDatabase.Tables)

{

    %>

     

        public override <%=this.RootNamespace%>.IDao.I<% = table.Name %>Dao <% = table.Name %>SqlProviderDao

        {

            get

            {



                //TODO:效率考虑,可考虑使用缓存



                SqlProviderDao.<% = table.Name %>SqlProviderDao obj = System.Web.HttpContext.Current.Cache.Get("<%=this.RootNamespace%>.IDao.I<% = table.Name %>Dao") as SqlProviderDao.<% = table.Name %>SqlProviderDao;

                if (obj == null)

                {

                    var instance = new SqlProviderDao.<% = table.Name %>SqlProviderDao();



                    System.Web.HttpContext.Current.Cache.Add("<%=this.RootNamespace%>.IDao.I<% = table.Name %>Dao",instance , null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);



                  //System.Web.HttpRuntime.Cache.Insert(

                    return instance;

                }



                return obj;







            }

        }

        

    <%

    }

    %>



   }

}

  

N层架构-数据访问层-SqlProviderDao Template

  • 数据访问层(DAAB)可以使用微软企业级框架 Microsoft Enterprise Library
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>

<%@ Property Name="CurrentTable" Type="SchemaExplorer.TableSchema" DeepLoad="True" Optional="False"  %>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Data;

using System.Data.SqlClient;

using <%=this.RootNamespace%>.Model;



namespace <%=this.RootNamespace%>.SqlProviderDao

{

    /// <summary>

    /// 对*<%= this.CurrentTable.Name %>*操作数据库(针对SQL Server)的实现

    /// </summary>

    public class <%= this.CurrentTable.Name %>SqlProviderDao:IDao.I<%= this.CurrentTable.Name %>Dao

    { 



 

        public int Add(Model.<%= this.CurrentTable.Name %> entity)

        {

            //通过DataBaseFactory获得当前数据库连接对象

             Database db=DatabaseFactory.CreateDatabase();

             SqlCommand cmd=db.GetStoredProcCommand("usp_<%=this.CurrentTable.Name%>_Insert") as SqlCommand;

            //cmd参数赋值

            <% foreach(ColumnSchema col in this.CurrentTable.Columns)

            {

            %>

                  cmd.Parameters.AddWithValue("@<%=col.Name%>",entity.<%=col.Name%>);

            <%}%>

             return db.ExecuteNonQuery(cmd);

            

        }



        public int Update(Model.<%= this.CurrentTable.Name %> entity)

        {

             //通过DataBaseFactory获得当前数据库连接对象

             Database db=DatabaseFactory.CreateDatabase();

             SqlCommand cmd=db.GetStoredProcCommand("usp_<%=this.CurrentTable.Name%>_Update") as SqlCommand;

            //cmd参数赋值

            <% foreach(ColumnSchema col in this.CurrentTable.Columns)

            {

            %>

                  cmd.Parameters.AddWithValue("@<%=col.Name%>",entity.<%=col.Name%>);

            <%}%>

             return db.ExecuteNonQuery(cmd);

        }



        public int Delete(Model.<%= this.CurrentTable.Name %> entity)

        {

           //根据主键进行删除数据,需要考虑出现复合主键

           //通过DataBaseFactory获得当前数据库连接对象

             Database db=DatabaseFactory.CreateDatabase();

             SqlCommand cmd=db.GetStoredProcCommand("usp_<%=this.CurrentTable.Name%>_Delete") as SqlCommand;

            //cmd参数赋值

            <% foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

            {

            %>

                  cmd.Parameters.AddWithValue("@<%=pkCol.Name%>",entity.<%=pkCol.Name%>);

            <%}%>

             return db.ExecuteNonQuery(cmd);

        

        }



        public List<Model.<%= this.CurrentTable.Name %>> LoadAllEntities()

        {

            //1.通过database工厂得到当前数据库连接的对象  db

            Database db = DatabaseFactory.CreateDatabase();

            //2.通过db 获得一个sp构成的cmd

            SqlCommand cmd = db.GetStoredProcCommand("usp_<% = this.CurrentTable.Name %>_LoadAll") as SqlCommand;



            //3.通过db执行一个DBReader



           SqlDataReader reader =  db.ExecuteReader(cmd) as SqlDataReader;

            //4.遍历DBReader,生成新的Entity对象,然后添加到List

            List<Model.<%= this.CurrentTable.Name %>> entitiesList=new  List<Model.<%= this.CurrentTable.Name %>>();

            while(reader.Read())

            {

                entitiesList.Add(new Model.<%=this.CurrentTable.Name%>(){

                    <%=this.SetValueToProperty %>

                });

            }

            return entitiesList;

        }



        public Model.<%= this.CurrentTable.Name %> LoadByPK(<%= PKArgsForTable()%>)

        {

           

            //1.通过database工厂得到当前数据库连接的对象  db

            Database db = DatabaseFactory.CreateDatabase();

            //2.通过db 获得一个sp构成的cmd

            SqlCommand cmd = db.GetStoredProcCommand("usp_<% = this.CurrentTable.Name %>_LoadByPK") as SqlCommand;

            

            <%foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

            {%>

                  cmd.Parameters.AddWithValue("@<% = pkCol.Name%>", <% = pkCol.Name%>);

            <%}%>



            //3.通过db执行一个DBReader



            SqlDataReader reader =  db.ExecuteReader(cmd) as SqlDataReader;

            //4.遍历DBReader,生成新的Entity对象,然后添加到List

            Model.<%=this.CurrentTable.Name%> one<%=this.CurrentTable.Name%>=null;

            if(reader.Read())

            {

                one<%=this.CurrentTable.Name%>=new <%=this.CurrentTable.Name%>(){

                    <%=this.SetValueToProperty %>

                };

            }

            return one<%=this.CurrentTable.Name%>;

        }

         #region ,当前表是子表,主表找子表

    

    <% foreach(TableKeySchema fk in this.CurrentTable.ForeignKeys)

    {

    %>

        public List<Model.<%=this.CurrentTable.Name%>> Query_<%=this.CurrentTable.Name%>List_By<%=fk.Name%>(<%=this.FKArgsForTable(fk)%>)

        {

              Database db = DatabaseFactory.CreateDatabase();

              SqlCommand cmd = db.GetStoredProcCommand("usp_<% = this.CurrentTable.Name %>_LoadBy_<%= fk.Name%>") as SqlCommand;

              //赋值:传递一个ForeignKey

              <%=this.SetPropertyValueByFK(fk)%>

            

             SqlDataReader reader =  db.ExecuteReader(cmd) as SqlDataReader;

             List<Model.<%= this.CurrentTable.Name %>> entitiesList=new  List<Model.<%= this.CurrentTable.Name %>>();

            while(reader.Read())

            {

                entitiesList.Add(new Model.<%=this.CurrentTable.Name%>(){

                    <%=this.SetValueToProperty %>

                });

            }

            return entitiesList;

            

            

        }

    <%}%>

    #endregion

     

    }

}

  







<script runat="template">



   private string SetPropertyValueByFK(TableKeySchema fk)

    {

        StringBuilder sb=new StringBuilder();

        foreach(MemberColumnSchema fkCol in fk.ForeignKeyMemberColumns)

        {

                sb.AppendFormat("cmd.Parameters.AddWithValue(\"@{0}\",{0});\r\n",fkCol.Column.Name);

        }

        return sb.ToString();

    }



    private string SetValueToProperty

    {

      get

        {

            string args="";

            foreach(ColumnSchema col in this.CurrentTable.Columns)

            {

                    args+=string.Format("{0}=({2})reader[\"{1}\"],",col.Name,col.Name,col.DataType);

            }

            return args.Substring(0,args.Length-1);

        }

        

    }



    //方法:生成列的主键列构成的参数列表

    public string PKArgsForTable()

    {

        string args="";

        foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

        {

                args += string.Format("{0} {1},",pkCol.Column.DataType,pkCol.Column.Name);  

        }

                   

         return args.Substring(0,args.Length-1);

    }

    

    //主键在子表中的外键所包含的列的参数列表带数据类型

    public string FKArgsForTable(TableKeySchema key){

      

         string args=""; 

        foreach(MemberColumnSchema Col in key.ForeignKeyMemberColumns)

        {

                args += string.Format("{1} {0},",Col.Column.Name,Col.DataType);

        }

                   

         return args.Substring(0,args.Length-1);

        }

</script>



                        

        

        

  

N层架构-SP存储过程-ScriptSp Template

  • 创建存储过程之前首先需要判读存储过程是否存在
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>

<%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False"  %>



--检查是否存在



use <%=this.SourceDatabase%>

go



<% foreach(TableSchema table in this.SourceDatabase.Tables){

%>

        

            if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<% = table.Name %>_Insert]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<% = table.Name %>_Insert]

            GO

            

            if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<% = table.Name %>_Update]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<% = table.Name %>_Update]

            GO

            

            if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<% = table.Name %>_Delete]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<% = table.Name %>_Delete]

            GO

            

            if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<% = table.Name %>_LoadAll]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<% = table.Name %>_LoadAll]

            GO

            

            if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<% = table.Name %>_LoadByPK]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<% = table.Name %>_LoadByPK]

            GO

            

            

            ------------------

              <%   foreach(TableKeySchema pk in table.ForeignKeys){

                            %>

                         if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[usp_<%= table.Name %>_LoadBy_<%= pk.Name%>]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

            drop procedure [dbo].[usp_<%= table.Name %>_LoadBy_<%= pk.Name%>]

            GO      

                         

                            <%

                            }

                            %>

            

            

            

            

<%

}%>









--生成存储过程

<%foreach(TableSchema table in SourceDatabase.Tables)

{%>

    --当前表示:<%=table.Name%>

    create proc usp_<%=table.Name%>_Insert

    (

       <%=this.CreateAllColumnsArgs(table)%>	

    )

as

insert into <%=table.Name%>(<%=this.CreateAllColumnsWithoutNativeType(table)%>) values(<%=this.CreateAllColumnsArgsWithoutNativeType(table)%>);



go

--------

create proc usp_<%=table.Name%>_LoadAll

as

select <%=this.CreateAllColumnsWithoutNativeType(table)%> from <%=table.Name%> 

go

--------

create proc usp_<%=table.Name%>_Delete

(

    <%=this.CreatePKColumnsArgs(table)%>

)

as

Delete from <%=table.Name%>

where

<%=this.CreatePKColumnsArgsWithoutNativeTypeAppendToWhere(table)%>;

go

--------



create proc usp_<%=table.Name%>_Update

(

	<%=this.CreateAllColumnsArgs(table)%>	

)

as

update <%=table.Name%> set <%=this.CreateAllColumnsArgsWithoutPK(table)%> where

<%=this.CreatePKColumnsArgsWithoutNativeTypeAppendToWhere(table)%>;



go

---------------

create proc usp_<%=table.Name%>_LoadByPK

(

     <%=this.CreatePKColumnsArgs(table)%>

)

as

select <%=this.CreateAllColumnsWithoutNativeType(table)%>

from

<%=table.Name%>

where

<%=this.CreatePKColumnsArgsWithoutNativeTypeAppendToWhere(table)%>



go

----------主外键关系,类的单一职责



    <%foreach(TableKeySchema fk in table.ForeignKeys)

    {%>

        create proc  usp_<%=table.Name%>_LoadBy_<%=fk.Name%> 

        (

            <%=this.CreateFK(fk)%>

        )

        as

        select  <%=this.CreateAllColumnsWithoutNativeType(table)%> from <%=table.Name%> 

        where <%=this.CreateFKSetValues(fk,table)%>

        go

        

        

    <%}%>





<%}%>

<script runat="template">

    //生成所有列的参数列表

    private string CreateAllColumnsArgs(TableSchema table)

    {

        string args="";

        foreach(ColumnSchema col in table.Columns)

        {

           if(col.NativeType=="varchar"|| col.NativeType=="nvarchar"||col.NativeType=="char"||col.NativeType=="nchar")

            {

                args+=string.Format("@{0} {1}({2}),",col.Name,col.NativeType,col.Size);            

            }

            else

            {

                args+=string.Format("@{0} {1},",col.Name,col.NativeType);

                

            }

        }

        return args.Substring(0,args.Length-1);

    }

    //生成所有列的列表,不带参数类型

    private string CreateAllColumnsWithoutNativeType(TableSchema table)

    {

        string args="";

        foreach(ColumnSchema col in table.Columns)

        {

                args+=string.Format("{0},",col.Name);

        

        }

        return args.Substring(0,args.Length-1);

    }

    //生成所有列的参数列表,不带参数类型

    private string CreateAllColumnsArgsWithoutNativeType(TableSchema table)

    {

        string args="";

        foreach(ColumnSchema col in table.Columns)

        {

                args+=string.Format("@{0},",col.Name);

        

        }

        return args.Substring(0,args.Length-1);        

    

    }

    

    //生成PK的参数列表

    private string CreatePKColumnsArgs(TableSchema table)

    {

        string args="";

        foreach(ColumnSchema col in table.Columns)

        {

            if(col.IsPrimaryKeyMember)

            {

                if(col.NativeType=="varchar"||col.NativeType=="nvarchar"||col.NativeType=="char"||col.NativeType=="nchar")

                {

                  args+=string.Format("@{0} {1}({2}),",col.Name,col.NativeType,col.Size);      

                }

                else

                {

                    args+=string.Format("@{0} {1},",col.Name,col.NativeType);    

                }

            }

        }

        return args.Substring(0,args.Length-1);

    }

    //生成主键列不带参数类型Where ID=@ID and...

    private string CreatePKColumnsArgsWithoutNativeTypeAppendToWhere(TableSchema table)

    {

        string args="";

        for(int i=0;i<table.PrimaryKey.MemberColumns.Count;i++)

        {

            args+=string.Format("{0}=@{0}",table.PrimaryKey.MemberColumns[i].Column.Name);

            if(i<table.PrimaryKey.MemberColumns.Count-1)

            {

                args +=string.Format(" and");   

            }

        }

        return args;

        

    }

    //非主键类型参数列表的赋值语句

    private string CreateAllColumnsArgsWithoutPK(TableSchema table)

    {

        string args="";

        foreach(ColumnSchema col in table.NonPrimaryKeyColumns)

        {

                args=string.Format("{0}=@{0},",col.Name);

        }

        if(table.NonPrimaryKeyColumns.Count==0)

        {

                return "";

        }

        return args.Substring(0,args.Length-1);

    }

    

    //主键在子表的引用外键所包含的列

    private string CreateFK(TableKeySchema fk)

    {

        string args=""; 

        foreach(MemberColumnSchema fkCol in fk.ForeignKeyMemberColumns)    

        {

                if(fkCol.NativeType=="varchar"||fkCol.NativeType=="nvarchar"||fkCol.NativeType=="char"||fkCol.NativeType=="nchar")

                {

                  args+=string.Format("@{0} {1}({2}),",fkCol.Column.Name,fkCol.Column.NativeType,fkCol.Column.Size);      

                }

                else

                {

                    args+=string.Format("@{0} {1},",fkCol.Column.Name,fkCol.Column.NativeType);    

                } 

        }

        return args.Substring(0,args.Length-1);

    }

    //根据外键表查找子表中多行的Where

    private string CreateFKSetValues(TableKeySchema fk,TableSchema table)

    {

        string args="";

        foreach(MemberColumnSchema fkCol in fk.ForeignKeyMemberColumns)

        {

            args+=string.Format("{0}.{1}=@{1},",table.Name,fkCol.Column.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    

</script>

 

N层架构-业务逻辑层-BLLTemplate

  • 业务逻辑层上一对多,多对一需要考虑清楚,还要考虑复合主键这类情况
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>

<%@ Property Name="CurrentTable" Type="SchemaExplorer.TableSchema" DeepLoad="True" Optional="False"  %>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>



using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace <%=this.RootNamespace%>.BLL

{

    public class <%= CurrentTable.Name%>

    {

        private 

        AbstractFactory.DaoFactory dataFactory = DataProvider.DefaultProvider;



        #region 增

        public int Add(Model.<%= CurrentTable.Name%> entity)

        {

            //通过工厂获得当前提供程序

            //用反射,通过web.config获得当前提供程序的名,再实例化





            return dataFactory.<%= CurrentTable.Name%>SqlProviderDao.Add(entity);

        }

        public int Add(<%=this.AllArgumentsForTable()%>)

        {



            return this.Add(new <%=this.RootNamespace%>.Model.<%= CurrentTable.Name%>()

            {

               <%=this.AllPropertiesSetValueForTable()%>



            });

        }



        #endregion



        #region 改

        public int Update(Model.<%= CurrentTable.Name%> entity)

        {

           

            return dataFactory.<%= CurrentTable.Name%>SqlProviderDao.Update(entity);



        }

        public int Update(<%=this.AllArgumentsForTable()%>)

        {

            return this.Update(new <%=this.RootNamespace%>.Model.<%= CurrentTable.Name%>()

            {

                  <%=this.AllPropertiesSetValueForTable()%>

            });



        }

        #endregion



        #region 删

        public int Delete(Model.<%= CurrentTable.Name%> entity)

        {

             return dataFactory.<%= CurrentTable.Name%>SqlProviderDao.Delete(entity);

        }

        public int Delete(<%= this.PKArgsForTable()%>)

        {

            return this.Delete(new <%=this.RootNamespace%>.Model.<%= CurrentTable.Name%>()

            {

                <%=this.PKPropertiesSetValueForTalble()%>

            });



        }

        #endregion



        #region Select

        public Model.<%= CurrentTable.Name%> Get<%= CurrentTable.Name%>ByPK(<%=this.PKArgsForTable()%>)

        {

   

            return dataFactory.<%=this.CurrentTable.Name%>SqlProviderDao.LoadByPK(<%=this.PKArgsWithoutDataTypeForTable()%>);

        }

        public List<Model.<%= CurrentTable.Name%>> GetAll<%=this.CurrentTable.Name%>List()

        {

            return dataFactory.<%=this.CurrentTable.Name%>SqlProviderDao.LoadAllEntities();



        }



        #endregion

        

               

        #region  当前表如果存在外键,找外键所在的主表

            <% foreach(TableKeySchema fk in this.CurrentTable.ForeignKeys)

            {%>

              public Model.<%=fk.PrimaryKeyTable.Name%> FindParentBy<%=fk.Name%>(<%=this.GetFKArgs(fk)%>)

              {

                     return this.dataFactory.<% = fk.PrimaryKeyTable.Name%>SqlProviderDao.LoadByPK(<%=GetFKArgsWithoutDataType(fk)%>);<% //= PKArgsWithoutDataTypeForTable(fk.PrimaryKeyTable)%>

              }

            

            <%}%>

        #endregion

        

         #region 主表找从表



   <%   foreach(TableKeySchema pk in this.CurrentTable.PrimaryKeys){

                

                    %>

                    

        //从当前表,找子表的List

             public List<Model.<%= pk.ForeignKeyTable.Name%>> Get<%= pk.ForeignKeyTable.Name%>ListBy<%= pk.Name%>(<%=this.FKArgsForTable(pk)%>)

        {

            

               return this.dataFactory.<%= pk.ForeignKeyTable.Name%>SqlProviderDao.Query_<%=pk.ForeignKeyTable.Name%>List_By<%=pk.Name%>(<%=this. FKArgsForTableWithoutDataType(pk) %>);

         

        }

        

        <%

        }

        %>

        #endregion

    }

    



      

       

}

        



<script runat="template">

    //方法:根据表,生成所有列构成的参数列表

    private string AllArgumentsForTable()

    {

        string args="";

        foreach(ColumnSchema col in CurrentTable.Columns)

        {

            args+=string.Format("{0} {1},",col.DataType,col.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    //生成实力类时初始化属性

    private string AllPropertiesSetValueForTable()

    {

              string args="";

        foreach(ColumnSchema col in CurrentTable.Columns)

        {

            args+=string.Format("{0}={1},",col.Name,col.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    //方法:生成列的主键列构成的参数列表

    private string PKArgsForTable()

    {

        string args="";

        foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

        {

            args+=string.Format("{0} {1},",pkCol.Column.DataType,pkCol.Column.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    //方法:生成主键列的赋值:

    public string PKPropertiesSetValueForTalble()

    {

       string args="";

       foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

       {

            args+=string.Format("{0}={1},",pkCol.Column.Name,pkCol.Column.Name); 

       }

       return args.Substring(0,args.Length-1);

    }

    //方法:生成主键列参数

    private string PKArgsWithoutDataTypeForTable()

    {

        string args="";

        foreach(MemberColumnSchema pkCol in this.CurrentTable.PrimaryKey.MemberColumns)

        {

            args+=string.Format("{0},",pkCol.Column.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    private string PKArgsWithoutDataTypeForTable(TableSchema table)

    {

        string args=""; 

        foreach(MemberColumnSchema pkCol in table.PrimaryKey.MemberColumns)

        {

                args += string.Format("{0},",pkCol.Column.Name);

        }

                   

         return args.Substring(0,args.Length-1);

    }

    //方法:按照某个FK,取他的列构成的参数列表(天啊,难道有复合外键吗)

    public string GetFKArgs(TableKeySchema fk)

    {

        string args="";

        foreach(MemberColumnSchema fkCol in fk.ForeignKeyMemberColumns)

        {

             args+=string.Format("{0} {1},",fkCol.Column.DataType,fkCol.Column.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    

    public string GetFKArgsWithoutDataType(TableKeySchema fk)

    {

        string args="";

        foreach(MemberColumnSchema fkCol in fk.ForeignKeyMemberColumns)

        {

             args+=string.Format("{0},",fkCol.Column.Name);

        }

        return args.Substring(0,args.Length-1);

    }

    

          //主键在子表中的外键所包含的列的参数列表

    public string FKArgsForTableWithoutDataType(TableKeySchema key){

      

         string args=""; 

        foreach(MemberColumnSchema Col in key.ForeignKeyMemberColumns)

        {

                args += string.Format("{0},",Col.Column.Name);

        }

                   

         return args.Substring(0,args.Length-1);

        }

        

          //主键在子表中的外键所包含的列的参数列表带数据类型

    public string FKArgsForTable(TableKeySchema key){

      

         string args=""; 

        foreach(MemberColumnSchema Col in key.ForeignKeyMemberColumns)

        {

                args += string.Format("{1} {0},",Col.Column.Name,Col.DataType);

        }

                   

         return args.Substring(0,args.Length-1);

        }

    

</script>

  

N层架构-单例模式-DefaultProvieder Template

  • 单例+反射
<%@ CodeTemplate  Inherits="CodeTemplate" Language="C#" TargetLanguage="Text"

 Description="NetTiers main template." Debug="True" ResponseEncoding="UTF-8"%>

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Name="System.Design" %>

<%@ Assembly Name="System.DirectoryServices" %>

<%@ Assembly Name="System.Web" %>

<%@ Assembly Name="System.Xml" %>



<%@ Import Namespace="SchemaExplorer" %>

<%@ Import NameSpace="System.IO" %>

<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 



<%-- 1. Datasource --%>



<%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False"%>



<%@ Property Name="RootNamespace" Default="MyOffice.Models" Type="System.String" Category="Context" Description="TargetTable that the object is based on." %>



using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace <%=this.RootNamespace%>.BLL

{

    internal class DataProvider

    {

        private static <%=this.RootNamespace%>.AbstractFactory.DaoFactory instance = null;



        static DataProvider()

        {          

            //.NET能保证这里的代码只执行一次

            //TODO:根据web.config 动态反射实例化数据工厂的实例

            //需要:提供程序的DLL文件名

            //         类名(完整名称)    命名空间.类名

            string dllfilename = System.Web.Configuration.WebConfigurationManager.AppSettings["DataProviderDllFile"];

            string daoFactoryClassName =

                System.Web.Configuration.WebConfigurationManager.AppSettings["DataProviderFactoryName"];



            //抽象工厂

            System.Reflection.Assembly dll = System.Reflection.Assembly.LoadFile(

                System.Web.HttpContext.Current.Server.MapPath("~/DataProviders/" + dllfilename));



            instance = dll.CreateInstance(daoFactoryClassName) as <%=this.RootNamespace%>.AbstractFactory.DaoFactory;





        }



        private DataProvider()

        {

        } 

        public static <%=this.RootNamespace%>.AbstractFactory.DaoFactory  DefaultProvider

        {

            get

            {

                return  instance;

            }

        }

    }

}

 

N层架构-主模板-Main Template

  • 添加指令集
<%@ Import NameSpace="System.Text" %>

<%@ Import NameSpace="System.Text.RegularExpressions" %>

<%@ Import NameSpace="System.Diagnostics" %>

<%@ Import NameSpace="System.Xml" %>

<%@ Import NameSpace="System.Xml.Xsl" %>

<%@ Import NameSpace="System.Xml.XPath" %> 
  • 注册子模板
<%@ Register Name="EntityClassTemplate" Template="Eyes.Entity.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="BizClassTemplate" Template="Eyes.Biz.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="IDALInterfaceTemplate" Template="Eyes.IDAL.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="DALFactoryTemplate" Template="Eyes.DALFactory.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="DALSqlFactoryTemplate" Template="Eyes.DALSqlFactory.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="SqlSPTemplate" Template="Eyes.SqlSp.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="DataProvider" Template="Eyes.Provider.cst" MergeProperties="False" ExcludeProperties="" %>

<%@ Register Name="DALSqlTemplate" Template="Eyes.DALSql.cst" MergeProperties="False" ExcludeProperties="" %>

<%--DataSourse--%>

<%@ Property Name="ChooseSourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False" Category="01. Getting Started - Required" Description="Database that the tables views, and stored procedures should be based on. IMPORTANT!!! If SourceTables and SourceViews are left blank, the Entire Database will then be generated." %>
  • 添加属性
<%--DataSourse--%>

<%@ Property Name="ChooseSourceDatabase" Type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False" Category="01. Getting Started - Required" Description="Database that the tables views, and stored procedures should be based on. IMPORTANT!!! If SourceTables and SourceViews are left blank, the Entire Database will then be generated." %>



<%@ Property Name="RootNamespace" Default="Net.Itcast.CN" Type="System.String" Optional="False"%>
  • 调用Script里面的创建模板方法

 

<%@ Property Name="RootNamespace" Default="Net.Itcast.CN" Type="System.String" Optional="False"%>

<%this.SaveEntityClasses();%>

<%this.GenerateBizClasses();%>

<%this.GenerateIDALInterface();%>

<%this.GenerateDALFactory();%>

<%this.GenerateDALSqlFactory();%>

<%this.GenerateDALSqlTemplate();%>

<%this.GenerateDataProvider();%>

<%this.GenerateSqlStoredProcedure();%>

<script runat="template">



    private string templateOutputDirectory=@"C:\Users\thinkpad\Desktop\ERPSolution\ERPSolution";

    

	[Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))] 

	[Optional, NotChecked]

	[Category("01. Getting Started - Required")]

	[Description("The directory to output the results to.")]

	[DefaultValue("")]

	public string OutputDirectory 

	{ 

		get

		{

			 return templateOutputDirectory;

		}

		set

		{

			if (value.EndsWith("\\")) value = value.Substring(0, value.Length - 1);

			templateOutputDirectory = value;

		} 

	}

    private void SaveEntityClasses()

    {

            CodeTemplate entityTemplate=new EntityClassTemplate();

            foreach(TableSchema table in this.ChooseSourceDatabase.Tables)

            {

                entityTemplate.SetProperty("CurrentTable",table);

                entityTemplate.SetProperty("RootNamespace",this.RootNamespace);

                entityTemplate.RenderToFile(this.templateOutputDirectory+@"\"+this.RootNamespace+@".Model\"+table.Name+".cs",true);

                Debug.WriteLine(table.Name);

            }

            

    }

   

    private void GenerateBizClasses()

    {

          CodeTemplate template = new BizClassTemplate();

            foreach(TableSchema table in this.ChooseSourceDatabase.Tables)

            {

                  template.SetProperty("CurrentTable",table);

                  template.SetProperty("RootNamespace",this.RootNamespace);

                  template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".BLL\"  + table.Name+".cs",true);

            }

           

    }

    

       private void GenerateIDALInterface()

    {

          CodeTemplate template = new IDALInterfaceTemplate();

            foreach(TableSchema table in this.ChooseSourceDatabase.Tables)

            {

                  template.SetProperty("CurrentTable",table);

                  template.SetProperty("RootNamespace",this.RootNamespace);

                  template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".IDAL\"  + "I"+table.Name+"Dao"+".cs",true);

            }

           

    } 

    private void GenerateDALSqlTemplate()

    {

          CodeTemplate template = new DALSqlTemplate();

            foreach(TableSchema table in this.ChooseSourceDatabase.Tables)

            {

                template.SetProperty("CurrentTable",table);

                template.SetProperty("RootNamespace",this.RootNamespace);

                template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".SqlProviderDao\"  + table.Name+"SqlDao"+".cs",true);

               

            }

           

    }

    

    

        private void GenerateDALFactory()

    {

         CodeTemplate template = new DALFactoryTemplate();

            template.SetProperty("SourceDatabase",this.ChooseSourceDatabase);

            template.SetProperty("RootNamespace",this.RootNamespace);

                template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".DaoFactory\DaoFactory.cs",true);

        

        }

        

            private void GenerateDataProvider()

    {

         CodeTemplate template = new DataProvider();

            template.SetProperty("SourceDatabase",this.ChooseSourceDatabase);

            template.SetProperty("RootNamespace",this.RootNamespace);

                template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".BLL\DataProvider.cs",true);

        

        }

       

        

          private void GenerateDALSqlFactory()

    {

         CodeTemplate template = new DALSqlFactoryTemplate();

            template.SetProperty("SourceDatabase",this.ChooseSourceDatabase);

            template.SetProperty("RootNamespace",this.RootNamespace);

                template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".SqlProviderDao\DaoSqlFactory.cs",true);

        

        }

        

          private void GenerateSqlStoredProcedure()

    {

         CodeTemplate template = new SqlSPTemplate();

            template.SetProperty("SourceDatabase",this.ChooseSourceDatabase);

            template.SetProperty("RootNamespace",this.RootNamespace);

                template.RenderToFile(this.templateOutputDirectory + @"\"+this.RootNamespace+@".SqlSPScript\SqlSPScript.sql",true);

        

        }

   

   

</script>

  

小结

上面的Ntier Tempalte不是最优化的,还有很多细节需要你考虑,比如数据类型的转换:

 

工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板

 

就像我开篇所说那样,工欲善其事,必先利其器,一套好的模板可以事半功倍,我在这儿抛砖引玉,期望于君共勉,打造属于自己的铜墙铁壁。

点击下载

你可能感兴趣的:(code)