博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

初次使用T4引擎生成数据库表实体

Posted on 2010-10-25 16:46  james.dong  阅读(903)  评论(1编辑  收藏  举报

网上看到有人使用T4来生成代码,发现这个东西自己没有接触过,因此google了一下,学习了一下相关的知识。

 现把自己学习的过程记录一下:

下面的代码主要是通过T4模板生成数据库表实体对象的过程。

1、首先我们需要实现 ITextTemplatingEngineHost 接口的类。该类存在"Microsoft.VisualStudio.TextTemplating.dll"中,因此我们需要在项目工程中引用此Dll文件。

下面是代码:

代码
 [Serializable]
    
public class TableHost : Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost {
        
private string _namespace = "JXDModel";
        
        
public string Namespace {
            
get { return _namespace; }
            
set { _namespace = value; }
        }

        
protected string _classname = "tablename";
        
public string Classname {
            
get { return _classname; }
            
set { _classname = value; }
        }
        
protected DataTable _dt = new DataTable();
        
public DataTable Dt {
            
get { return _dt; }
            
set { _dt = value; }
        }

        
protected string _templateFile = "";
        
public string TemplateFile {
            
get { return _templateFile; }
            
set { _templateFile = value; }
        }
        
protected string _fileExtension = ".cs";
        
public string FileExtension {
            
get { return _fileExtension; }
            
set { _fileExtension = value; }
        }
        
public IList<string> StandardAssemblyReferences {
            
get {
                
return new string[]
            {
                
typeof(System.Uri).Assembly.Location,
                
typeof(TableHost).Assembly.Location,
                
typeof(DbType).Assembly.Location,
                
typeof(XmlDataDocument).Assembly.Location,
                
typeof(System.Xml.Serialization.XmlSchemas).Assembly.Location,
                
typeof(System.AppDomain ).Assembly.Location 
            };
            }
        }
        
public IList<string> StandardImports {
            
get {
                
return new string[]
        { 
            
"System",
            
"System.Data",
            
"System.IO",
            
"System.Xml",
            
"System.Xml.Serialization",
            
"System.Text",
            
"windows2008",
            
"System.Data.Common",
            
"System.Collections",
            
"System.Collections.Generic",
            
"System.Collections.Specialized"
        };
            }
        }

        
public object GetHostOption(string optionName) {
            
object returnObject;
            
switch (optionName) {
                
case "CacheAssemblies":
                    returnObject 
= true;
                    
break;
                
default:
                    returnObject 
= null;
                    
break;
            }
            
return returnObject;
        }

        
public void SetFileExtension(string extension) {
            _fileExtension 
= extension;
        }

        
private System.Text.Encoding _fileEncodingValue = System.Text.Encoding.UTF8;
        
public void SetOutputEncoding(System.Text.Encoding encoding, bool fromOutputDirective) {
            _fileEncodingValue 
= encoding;
        }

        
private CompilerErrorCollection _errorsValue;
        
public CompilerErrorCollection Errors {
            
get { return _errorsValue; }
        }

        
public void LogErrors(CompilerErrorCollection errors) {
            _errorsValue 
= errors;
        }
        
public string ResolvePath(string fileName) {
            
return fileName;
        }
        
public bool LoadIncludeText(string requestFileName, out string content, out string location) {
            content 
= System.String.Empty;
            location 
= System.String.Empty;

            
//If the argument is the fully qualified path of an existing file,
            
//then we are done.
            
//----------------------------------------------------------------
            if (File.Exists(requestFileName)) {
                content 
= File.ReadAllText(requestFileName);
                
return true;
            }

            
//This can be customized to search specific paths for the file.
                
//This can be customized to accept paths to search as command line
                
//arguments.
                
//----------------------------------------------------------------
            else {
                
return false;
            }
        }
        
public string ResolveAssemblyReference(string assemblyReference) {
            
if (File.Exists(assemblyReference)) {
                
return assemblyReference;
            }
            
string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
            
if (File.Exists(candidate)) {
                
return candidate;
            }
            
return "";
        }
        
public Type ResolveDirectiveProcessor(string processorName) {
            
throw new Exception("Directive Processor not found");
        }

        
public string ResolveParameterValue(string directiveId, string processorName, string parameterName) {
            
if (directiveId == null) {
                
throw new ArgumentNullException("the directiveId cannot be null");
            }
            
if (processorName == null) {
                
throw new ArgumentNullException("the processorName cannot be null");
            }
            
if (parameterName == null) {
                
throw new ArgumentNullException("the parameterName cannot be null");
            }

            
//Code to provide "hard-coded" parameter values goes here.
            
//This code depends on the directive processors this host will interact with.

            
//If we cannot do better, return the empty string.
            return String.Empty;
        }
        
public AppDomain ProvideTemplatingAppDomain(string content) {
            
//This host will provide a new application domain each time the 
            
//engine processes a text template.
            
//-------------------------------------------------------------
            return AppDomain.CreateDomain("Generation App Domain");

            
//This could be changed to return the current appdomain, but new 
            
//assemblies are loaded into this AppDomain on a regular basis.
            
//If the AppDomain lasts too long, it will grow indefintely, 
            
//which might be regarded as a leak.

            
//This could be customized to cache the application domain for 
            
//a certain number of text template generations (for example, 10).

            
//This could be customized based on the contents of the text 
            
//template, which are provided as a parameter for that purpose.
        }
    }

 下载代码实例: /Files/james-dong/T42008.rar

2、编写生成对象实体的模板文件(.tt) 

代码
<#@ Template language="C#" debug="true" hostspecific="true" #>
<#@ Assembly name = "System.Data" #>
<#@ Assembly name = "System.Xml" #>
<#@ import Namespace = "System.Data" #>
<#@ import Namespace = "System.Data.SqlClient" #>
<#@ import Namespace = "System.Xml" #>
<#@ output extension= ".cs" #>

using System;
using system.Data;

<#
  TableHost host 
= (TableHost)(Host);
  
string namespacess = host.Namespace;
  
string classname = host.Classname;
  DataTable dt 
= host.Dt;
#
>



namespace <#=namespacess #>
{
    
public class <#= classname #>
    {
      
<#
        
foreach( DataColumn dc in dt.Columns )
        {
      #
>
          
private <#= dc.DataType.Name.ToString().ToLower() #> _<#= dc.ColumnName.ToString().ToLower() #>;
          
public <#= dc.DataType.Name.ToString().ToLower() #> <#= dc.ColumnName.ToString().ToUpper() #>
          {
            
getreturn _<#= dc.ColumnName.ToString().ToLower()#>; }
            
set{ _<#=dc.ColumnName.ToString().ToLower()#>= value; }
          }
      
<#  
        }
      #
>
    }    
}





 

3、调用T4引擎生成实体过程

代码
public void Process(string namespace , string classname , string templatefile , string connstring ) {
            TableHost host 
= new TableHost();
            host.Namespace 
= namespace ;
            host.Classname 
= classname ;
            host.FileExtension 
= ".cs";
            host.TemplateFile 
= templatefile;                    

            SqlConnection conn 
= new SqlConnection(constring);
            conn.Open();
            DataTable dt 
= conn.GetSchema("tables");            
            
string sql = "select * from " + host.Classname;
            SqlCommand cmd 
= new SqlCommand(sql, conn);
            SqlDataAdapter ad 
= new SqlDataAdapter(cmd);
            DataSet ds 
= new DataSet();
            ad.FillSchema(ds, SchemaType.Mapped, host.Classname );
            host.Dt 
= ds.Tables[0];

            Microsoft.VisualStudio.TextTemplating.Engine engine 
= new Microsoft.VisualStudio.TextTemplating.Engine();
            
string input = "";
            
string output = "";
            input 
= System.IO.File.ReadAllText(host.TemplateFile);
            output 
= engine.ProcessTemplate(input, host);

            
string outputname = host.Classname + host.FileExtension;

            System.IO.File.WriteAllText(outputname  , output);

            
foreach (CompilerError error in host.Errors) {
                textBox1.Text 
+= error.ToString();
            }

 

 

到此,一个简单的数据库表实体类的功能就实现了。