工欲善其事,必先利其器:分享一套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

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不是最優化的,還有很多細節需要你考慮,比如數據類型的轉換:

 

 

就像我開篇所說那樣,工欲善其事,必先利其器,一套好的模板可以事半功倍,我在這兒拋磚引玉,期望於君共勉,打造屬於自己的銅牆鐵壁。

點擊下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM