现在的位置: 首页 > 综合 > 正文

使用C#打造代码生成器

2012年05月11日 ⁄ 综合 ⁄ 共 11041字 ⁄ 字号 评论关闭

使用C#打造代码生成器

作者:陈缘
联系:luandao2000@gmail.com
博客:http://blog.csdn.net/luandao2000
主页:http://www.spbase.com

        使用VS.NET开发WEB应用的同志都会接触到.NET平台上两个非常经典的例子:Duwamish和Petshop,两个例子都是微软为了演示n层架构而开发的示例,因为是微软内部不同的小组所开发所以风格差异较大。孰优孰劣我不敢妄作评价,但在我目前所作的项目中全部是采用Duwamish的结构来设计整个系统的,就目前的情况来开,效果还是比较好的。
        Duwamish的数据表示层完成数据表到业务实体的映射,采用有类型的DataSet来描述业务实体的结构,这部分代码依赖于构成业务实体的数据表的结构,大家从Duwamish的实现也可以看到这点。表示层的代码格式简单,没有任何逻辑,基本上只是描述了结构而已,所以对于这部分代码可以采用代码生成器来完成。
        下来看看数据访问层,基本上类似,数据访问层完成实际的数据读写工作,但大部分简单的增、删、改、查的代码还是比较简单,格式比较固定:先构造存储过程的入口参数,构造相应操作的Command对象,调用适配器完成操作,如果没有特殊的要求,这部分代码的完成也可以自动生成。
        好了分析完成代码的格式后,我们来考虑一下我们需要一个什么样的代码生成器呢?首先,能根据构成业务实体的数据表格式生成表示层和数据访问层的代码,其次必须要能支持相应的配置。这样基本上可以减少很多重复性的工作。对采用Duwamish架构的系统来说,可以生成对的业务实体的一些简单操作,最后最好能自动生成增删改的存储过程,这样基本上就完成了一个数据库系统的雏形。
        实际上大部分的代码生成器也就是完成这些功能,根据你的选择生成一个模板性质的代码,这样很多工作就不用再重复作,后期维护时也会方便很多。
        好了废话就不再说了,开始动手:
1、先设计各个层的模板文件和替换的参数
2、根据选择的数据表生成动态代码部分
3、生成相应的代码文件和存储过程

       先说各个层的模板文件,其实参考一下表示层的代码可以很明显看出来:有类型DataSet所描述的数据实体基本只是数据表在程序中的映射而已,当然我们必须考虑Master-Detail表的关系,大部分的业务实体不是单独一个数据表能描述清楚的。这里给出一个数据访问层模板文件的示例:

namespace ServiceCard.DataAccess
{
 using System;
 using System.ComponentModel;
 using System.Data;
 using System.Data.OracleClient;
 using System.Configuration;
     using ServiceCard.Common;
 
 

 /// <summary>
 /// Card info
 /// </summary>
 public class $classname$ : AccessBase
 {
  //
  // DataSetCommand object
  //
  //private OracleDataAdapter dsCommand;
  //
  // Stored procedure parameter names
  //
  private OracleCommand loadCommand;
  private OracleCommand insertCommand;
  private OracleCommand updateCommand;
  private OracleCommand deleteCommand;
  //private string ServiceCardConnectionString=ConfigurationSettings.AppSettings["ServiceCardConnectionString"];

  private const string PROCESS_PARM  = "GH_PACKAGE.LOAD_WORKSHEET";
  private const string CURSOR_PARM  = "ret_cur";
  private const string VALUE_PARM   = "in_value";
  
  
  $parm$ 

  
  public $classname$()
  {
   //
   // TODO: add your code
   //
   dsCommand = new OracleDataAdapter();
       
   dsCommand.TableMappings.Add("$tablename$", $dataname$.$constname$);
  }
  
  public $classname$(OracleConnection base_connect,OracleTransaction base_mytrans)
  {
   //
   // TODO: add your code
   //
   dsCommand = new OracleDataAdapter();
       
   dsCommand.TableMappings.Add("$tablename$", $dataname$.$constname$);
   
   connect=base_connect;
   mytrans=base_mytrans;
   bTrans=true;
  }

  /// <summary>
  ///     Dispose of this object's resources.
  /// </summary>
  //public void Dispose()
  //{
  // Dispose(true);
  // GC.SuppressFinalize(true); // as a service to those who might inherit from us
  //}

  /// <summary>
  ///  Free the instance variables of this object.
  /// </summary>
  ///protected override void Dispose(bool disposing)
  ///{
  /// if (! disposing)
  ///  return; // we're being collected, so let the GC take care of this object
  /// 
  /// if (dsCommand != null)
  /// {
  ///  if(dsCommand.SelectCommand != null)
  ///  {
  ///   if( dsCommand.SelectCommand.Connection != null  )
  ///   {
  ///    dsCommand.SelectCommand.Connection.Dispose();
  ///   }
  ///   dsCommand.SelectCommand.Dispose();
  ///  }   
  ///  dsCommand.Dispose();
  ///  dsCommand = null;
  /// }
  ///}
  //----------------------------------------------------------------
  // Sub BuildLoadCommands:
  //   Initialize the parameterized Load command for the DataAdapter
  //----------------------------------------------------------------
  private OracleCommand GetLoadCommand()
  {
   if ( loadCommand == null )
   {
    //
    // Construct the command since we don't have it already
    //
    
    loadCommand = new OracleCommand(PROCESS_PARM,new OracleConnection (ServiceCardConnectionString));
    loadCommand.CommandType = CommandType.StoredProcedure;

          
    loadCommand.Parameters.Add(new OracleParameter(CURSOR_PARM, OracleType.Cursor));

    loadCommand.Parameters[CURSOR_PARM].Direction = ParameterDirection.Output;

    loadCommand.Parameters.Add(new OracleParameter(VALUE_PARM, OracleType.VarChar));

    
    
   }
           
   return loadCommand;
  }

  private OracleCommand GetDeleteCommand()
  {
   if ( deleteCommand == null )
   {
    //
    // Construct the command since we don't have it already
    //
    if(bTrans)
        deleteCommand = new OracleCommand("$deletecommand$",connect);
    else
        deleteCommand = new OracleCommand("$deletecommand$",new OracleConnection (ServiceCardConnectionString));
    deleteCommand.CommandType = CommandType.StoredProcedure;
    deleteCommand.Transaction = mytrans;
    
    OracleParameterCollection OracleParams = deleteCommand.Parameters;
    
    $deleteconest$
    
   }
           
   return deleteCommand;
  }

  private OracleCommand GetUpdateCommand()
  {
   if ( updateCommand == null )
   {
    //
    // Construct the command since we don't have it already
    //
    if(bTrans)
        updateCommand = new OracleCommand("$updatecommand$",connect);
    else
        updateCommand = new OracleCommand("$updatecommand$",new OracleConnection (ServiceCardConnectionString));
       
    updateCommand.CommandType = CommandType.StoredProcedure;
    updateCommand.Transaction = mytrans;
    
    OracleParameterCollection OracleParams = updateCommand.Parameters;
          
    $updateparmadd$
    
    //
    // Define the parameter mappings from the data table in the
    // dataset.
    //
    $updateprarmequ$
     
    
   }
           
   return updateCommand;
  }

  //----------------------------------------------------------------
  // Sub BuildInsertCommands:
  //   Initialize the parameterized Load command for the DataAdapter
  //----------------------------------------------------------------
  private OracleCommand GetInsertCommand()
  {
   if ( insertCommand == null )
   {
    //
    // Construct the command since we don't have it already
    //
    if(bTrans)
        insertCommand = new OracleCommand("$insertcommand$",connect);
    else
        insertCommand = new OracleCommand("$insertcommand$",new OracleConnection (ServiceCardConnectionString));
       
    insertCommand.CommandType = CommandType.StoredProcedure;
           insertCommand.Transaction = mytrans;
            
    OracleParameterCollection OracleParams = insertCommand.Parameters;
           
    $updateparmadd$ 

    
    //
    // Define the parameter mappings from the data table in the
    // dataset.
    //
    $updateprarmequ$
   }
           
   return insertCommand;
  }

  /// <summary>
  ///     Inserts a new card into the database.
  ///     <param name="card">A CardData containing detailed card information.</param>
  ///     <retvalue>Success or failure of the database insert.</retvalue>
  /// </summary>
  public bool Insert$workobject$($dataname$ $paraname$)
  {
   if ( dsCommand == null )
   {
    throw new System.ObjectDisposedException( GetType().FullName );
   }           
           
   dsCommand.InsertCommand = GetInsertCommand();
           
   dsCommand.Update($paraname$, $dataname$.$constname$);
   //
   // Check for table errors to see if the update failed.
   //
   if ( $paraname$.HasErrors )
   {
    $paraname$.Tables[$dataname$.$constname$].GetErrors()[0].ClearErrors();
    return false;
   }
   else
   {
    $paraname$.AcceptChanges();
    return true;
   }
  }

  /// <summary>
  ///     Inserts a new card into the database.
  ///     <param name="card">A CardData containing detailed card information.</param>
  ///     <retvalue>Success or failure of the database insert.</retvalue>
  /// </summary>
  public $dataname$ Load$workobject$(string SN)
  {
   if ( dsCommand == null )
   {
    throw new System.ObjectDisposedException( GetType().FullName );
   }
   $dataname$ $paraname$ = new $dataname$();
   dsCommand.SelectCommand=GetLoadCommand();
   dsCommand.SelectCommand.Parameters[VALUE_PARM].Value = SN;
   
   dsCommand.Fill($paraname$,$dataname$.$constname$);
   //
   // Check post conditions
   //       

           
   return $paraname$;
  }

  public bool Update$workobject$($dataname$ $paraname$)
  {
   if ( dsCommand == null )
   {
    throw new System.ObjectDisposedException( GetType().FullName );
   }
  
   dsCommand.UpdateCommand=GetUpdateCommand();
     
   dsCommand.Update($paraname$, $dataname$.$constname$);
   //
   // Check for table errors to see if the update failed.
   //
   if ( $paraname$.HasErrors )
   {
    $paraname$.Tables[$dataname$.$constname$].GetErrors()[0].ClearErrors();
    return false;
   }
   else
   {
    $paraname$.AcceptChanges();
    return true;
   }
   
  }

  public bool Delete$workobject$(string thekey)
  {
   bool result=false;
   OracleCommand deleteCommand=new OracleCommand("$deletecommand$",new OracleConnection (ServiceCardConnectionString));
   deleteCommand.Connection.Open();
   deleteCommand.CommandType=CommandType.StoredProcedure;
   
   deleteCommand.Parameters.Add(new OracleParameter(CHARGE_CODE_PARM, OracleType.VarChar, 10));
   deleteCommand.Parameters[CHARGE_CODE_PARM].Value=charge_code;
   try
   {
    deleteCommand.ExecuteNonQuery();
    result=true;
   }
   catch(Exception ex)
   {
    result=false;
    throw new Exception(ex.Message);
   }
   finally
   {
    deleteCommand.Connection.Close();
    deleteCommand.Connection.Dispose();
    deleteCommand.Parameters.Clear();
    deleteCommand.Dispose();
   }
   return result;
   
   
  }

 }
}

      模板文件很简单:和数据表格式相关的地方采用标签来代替,程序中根据表的结构、关联生成这部分代码并且模板文件中的标签设置生成最终代码。

替换部分的代码如下:

private StringBuilder ReplaceValue(StringBuilder content)
  {
   constList.Clear();
   valueList.Clear();
   InitConstList();
   InitValueList();
   int index=0;
   foreach (string item in constList)
   {
    content.Replace(item,valueList[index].ToString());
    index+=1;

   }
   return content;
  }

  private void InitConstList()
  {
   string str="";
   
   //1
   str="$classname$"; 
   constList.Add(str);
   //2
   str="$parm$";   
   constList.Add(str);
   //3
   str="$tablename$";  
   constList.Add(str);
   //4
   str="$dataname$";  
   constList.Add(str);
   //5
   str="$constname$";  
   constList.Add(str);
   //6
   str="$loadcommand$"; 
   constList.Add(str);
   //7
   str="$deletecommand$"; 
   constList.Add(str);
   //8
   str="$deleteconest$";
   constList.Add(str);
   //9
   str="$insertcommand$";
   constList.Add(str);
   //10
   str="$updatecommand$";
   constList.Add(str);
   //11
   str="$updateparmadd$";
   constList.Add(str);
   //12
   str="$updateprarmequ$";
   constList.Add(str);
   //13
   str="$paraname$";
   constList.Add(str);

   //14
   str="$systemclassname$";
   constList.Add(str);
   //15
   str="$workobject$";
   constList.Add(str);

  }
  
  private void InitValueList()
  {
   string str="";
   //$classname$  =类名1 数据访问层类名称
   str=DataName.Text+"s";//ClassName.Text;
   valueList.Add(str);
   //$parm$   =声明存储过程需要的参数2
   str=t1;
   valueList.Add(str);
   //$tablename$  =数据库中的表名3
   str=strTablename;
   valueList.Add(str);
   //$dataname$  =表示层 该数据对象的类名4
   str=DataName.Text+"Data";
   valueList.Add(str);
   //$constname$  =表示层 该数据对象表名的常量名5
   str=strTablename+"_TABLE";
   valueList.Add(str);
   //$loadcommand$  =加载存储过程名6
   str="LOAD_"+strTablename;
   valueList.Add(str);
   //$deletecommand$  =删除存储过程名7
   str="DELETE_"+strTablename;
   valueList.Add(str);
   //$deleteconest$  =删除参数说明8
   str="//you shuld add delete parm ";
   valueList.Add(str);
   //$insertcommand$  =新增存戳过程名9
   str="INSERT_"+strTablename;;
   valueList.Add(str);
   //$updatecommand$  =更新存储过程名10
   str="UPDATE_"+strTablename;;
   valueList.Add(str);
   //$updateparmadd$  =增加更新需要的参数11
   str=t2;
   valueList.Add(str);
   //$updateprarmequ$ =制定这些参数的源列12
   str=t3;
   valueList.Add(str);
   //$paraname$  =从逻辑层传输的业务对象 名称13
   str=DataName.Text.ToLower();;
   valueList.Add(str);

   //增加业务逻辑层的处理
   str=DataName.Text+"System";
   valueList.Add(str);

   //增加对象
   str=DataName.Text;
   valueList.Add(str);

  }

 

  大体思想已经描述清楚 需要源码请来信索取

抱歉!评论已关闭.