程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#發現之旅第三講 使用C#開發基於XSLT的代碼生成器(1)

C#發現之旅第三講 使用C#開發基於XSLT的代碼生成器(1)

編輯:關於C#

為了讓大家更深入的了解和使用C#,我們開始這一系列的主題為“C#發現之旅 ”的技術講座。考慮到各位大多是進行WEB數據庫開發的,而所謂發現就是發現我們所 不熟悉的領域,因此本系列講座內容將是C#在WEB數據庫開發以外的應用。目前規劃的主要內 容是圖形開發和XML開發,並計劃編排了多個課程。在未來的C#發現之旅中,我們按照由淺入 深,循序漸進的步驟,一起探索和發現C#的其他未知的領域,更深入的理解和掌握使用C#進 行軟件開發,拓寬我們的視野,增強我們的軟件開發綜合能力。

本課程說明

經過以前的學習,我們大體上了解了XML/XSLT開發,在本課程中,我們將在ASP.NET中使用C# 開發一個基於XSLT技術的代碼生成器。

代碼生成器

首先說說什麼是代碼生成 器。個人認為是一種工具軟件,它能根據某種已經固定的信息,使用程序來機械的大批量的 生成有結構上有比較簡單規律的源代碼,從而減少軟件開發人員的編碼量。

從廣義上 講,我們寫的WEB數據庫程序都是代碼生成器,它們能根據保存在數據庫中的固定數據自動生 成大量的HTML代碼。在這裡我們限制代碼生成器為通用代碼生成器。代碼生成器主要功能是 幫助程序員自動生成大量的底層代碼,這種代碼可以是C#或Java的程序源代碼,也可以是SQL 語句,或者HTML代碼等等,是一種軟件開發過程中的輔助工具軟件。

我們最常用的代 碼生成器是根據數據庫結構自動生成能操作數據庫記錄的程序源代碼,SQL語句或其他文檔等 等。對於這種代碼生成器,其數據信息來源就是數據庫的表結構和字段屬性等信息,我們可 以分析遍歷數據庫的系統表來貨的表結構和字段信息,也可以從PowerDesigner等數據結構設 計器保存的文檔中獲得。

針對某個特定的項目,我們可以根據數據庫結構臨時寫一個 代碼生成器,使用字符串拼湊來生成源代碼,但這種代碼生成器不通用,難於用於其他項目 。因此我們更多的是使用通用的代碼生成器。

很多通用代碼生成器的原理如圖

在這個圖中,我們看到代碼生成器包含了模板庫和代碼生成器處理引擎,模板庫包 含了若干個模板,一個模板一般是純文本,其中可能包含了腳本代碼,或者類似ASP的結構。 生成器引擎加載一個或者多個數據庫表結構設計信息,然後調用用戶指定的模板,通過某種 操作來自動生成另外一個文本文件,這個文本文件內容可以是純文本,HTML代碼,C#代碼或 者其他。

考察這個結構,可以發現這個原理和XSLT原理很相似。我們可以將數據庫表 結構設計信息保存在一個XML文檔中,代碼生成器模板就使用XSLT格式,代碼生成器引擎就使 用XSLT轉換引擎,這樣我們也可以達到代碼生成器的功能,從而搞出基於XSLT的代碼生成器 。

軟件設計

根據基於XSLT來實現代碼生成功能的思路,我們開始設計這個代 碼生成器。

數據來源

這個代碼生成器的數據來源就是數據庫表結構設計信息 。對於不同的數據庫類型得使用不同的方法來獲得其表結構設計信息。在此我們針對於 Access2000,MSSQLServer和Oracle這三種數據庫研究獲得其表設計信息的方法,對於其他類 型的數據庫則以後再說。

對於MSSQLServer,數據庫中有SysObjects和SysColumns這 兩個系統表,我們可以查詢系統表來獲得所有的表名稱和字段名稱以及格式,還有一個 sp_helpindex 的系統預定義存儲過程來獲得指定表的字段索引信息。

對於Oracle, 數據庫有一個名為Col的系統預定義視圖,我們可以查詢這個視圖獲得所有的表名和字段定義 信息。還有一個user_ind_columns的系統預定義視圖,我們可以關鍵字段信息。

對於 Access2000數據庫,沒有這些系統表,因此我們使用。NET框架中的OleDB的數據連接對象的 GetOleDbSchemaTable函數來獲得數據庫表和字段定義信息。

我們的代碼生成器還應 當從一下數據結構設計器生成的文檔導入表結構設計信息,這裡我們決定從PowerDesigner生 成的PDM文件中導入表設計信息,因為PDM文件是XML格式的,處理方便。

代碼生成模 板

這裡的代碼生成模板就采用XSLT格式。為了方便軟件開發和維護,我們將模板保存 在程序目錄下的XSLT擴展名的文件中,並約定文件名使用下劃線開頭。

程序

在這裡使用ASP.NET中實現該代碼生成器,使用.NET框架自帶的XSLT轉換對象來作為代碼生成 器處理引擎,並使用HTML格式來展示生成的源代碼。

程序說明

根據上述的軟 件設計,我們開發出了這個代碼生成器,現對其源代碼進行詳細說明。

xslcreatecode.aspx

本代碼生成器很簡單,只有一個ASPX頁面,打開該頁面 的設計界面,

可以看到上 面放置了一些簡單的控件。其中比較重要的有

數據表名下拉列表,該列表列出了數據 庫中所有數據表的名稱。

XSLT模板名稱下拉列表,該列表列出了所有系統可用的XSLT 模板文件的名稱。

刷新系統按鈕,用於刷新系統數據設置,重新填充數據表名列表和 模板名列表。

創建代碼,根據當前選擇的數據表名和XSLT模板名稱創建代碼。

生成的源代碼文本標簽,使用HTML格式來顯示生成的源代碼。

打開這個頁面 的C#代碼,可以看到其代碼也不復雜。這個頁面的Page_Load函數調用了刷新系統的方法 RefreshSystem。

/// <summary>
/// 刷新系統
/// </summary>
private void RefreshSystem( )
{
  DataBaseInfo info = this.GetInfo();
  this.lblResult.Text = info.Name ;
  if( cboTable.Items.Count == 0 )
  {
    cboTable.Items.Add( new ListItem("所有表" , "所有表" ));
    foreach( TableInfo table in info.Tables )
    {
       cboTable.Items.Add( new ListItem( table.Name , table.Name ));
    }
  }
  if( cboXSLT.Items.Count == 0 )
  {
     cboXSLT.Items.Add("XML代碼");
    string[] names = System.IO.Directory.GetFiles( this.MapPath(".") , "_*.xslt");
    if( names != null && names.Length > 0 )
    {
      foreach( string name in names )
       {
        string name2 = System.IO.Path.GetFileNameWithoutExtension( name );
         this.cboXSLT.Items.Add( new ListItem( name2 , name2 ));
      }
    }
  }
}//private void RefreshSystem( )
/// <summary>
/// 獲得數據庫結構信息對象
/// </summary>
/// <returns>數據庫結構信息對象</returns>
private DataBaseInfo GetInfo( )
{
  DataBaseInfo info = this.Session["info"] as DataBaseInfo ;
  if( info == null )
  {
    info = new DataBaseInfo();
    info.LoadFromAccess2000( this.MapPath ("demomdb.mdb"));
    this.Session["info"] = info ;
  }
  return info ;
}   

在RefreshSystem方法 中,首先獲得數據庫結構信息對象,遍歷其中的表結構信息對象,向數據表名下列列表填充 項目。

遍歷網站目錄下的所有以下劃線開頭的XSLT文件,將其文件名填充到XSLT模板 下拉列表中。

這裡使用了另外一個函數GetInfo,該函數就是獲得系統使用的數據庫 結構信息對象,它是緩存在session中的對象,它使用了程序目錄下的演示數據庫作為數據結 構信息來源。

頁面代碼中還有強制刷新系統按鈕事件處理。

/// <summary>
/// 刷新系統按紐事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cmdRefresh_Click(object sender, System.EventArgs e)
{
  this.Session["info"] = null;
  this.cboTable.Items.Clear();
  this.cboXSLT.Items.Clear ();
  RefreshSystem( );
}//private void cmdRefresh_Click(object sender, System.EventArgs e)

這個處理過程比較簡單,將緩存的數據結構信 息對象刪除掉,清空數據表名列表和模板列表,然後調用RefreshSystem方法刷新界面。

這個頁面最重要的代碼就是自動生成並顯示代碼的過程了。其C#代碼為

/// 創建代碼按紐事件 
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cmdCreate_Click(object sender, System.EventArgs e)
{
DataBaseInfo info = this.GetInfo();
string xml = null ;
if( cboTable.SelectedIndex == 0 )
{
xml = GetXMLString( info );
}
else
{
TableInfo table = info.Tables[ this.cboTable.SelectedValue ] ;
if( table == null )
{
this.lblResult.Text = "請選擇一個表";
return ;
}
xml = GetXMLString( table );
}
string html = "";
if( cboXSLT.SelectedIndex <= 0 )
{
// 沒有使用任何模板,直接顯示XML源代碼
html = @"<textarea
wrap=off
readonly
style='border:1 solid black;
overflow=visible;
background-color:#dddddd'>"
+ xml + "</textarea>";
}
else
{
// 啟動了XSLT模板,執行XSLT轉換
System.Xml.Xsl.XslTransform transform = new System.Xml.Xsl.XslTransform();
transform.Load( this.Server.MapPath( this.cboXSLT.SelectedValue ) + ".xslt" );
System.IO.StringWriter writer = new System.IO.StringWriter();
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml( xml );
transform.Transform( doc , null , writer , null );
writer.Close();
html = writer.ToString();
}
this.lblResult.Text = "<b>共生成 "
+ html.Length
+ " 個字符</b><br />\r\n" + html ;
}

在生成代碼按鈕事件處理中,首先根據數據表名列表獲得當前數據 表結構信息對象,並生成XML字符串。若用戶指定了某個數據表則調用GetXMLString函數來生 成該數據表的XML字符串,否則對整個數據結構信息對象生成XML字符串。

若用戶沒有 指定XSLT模板,則生成直接顯示XML代碼的HTML代碼。這裡使用textarea元素來顯示XML代碼 ,這樣XML代碼顯示時不需要進行轉義處理。

若用戶指定了XSLT模板名稱,則創建一 個XslTransform對象,使用Load方法從程序目錄中加載該名稱的XSLT模板文件。這裡可以看 出我們的程序需要訪問程序目錄的權限,因此部署這個代碼生成器時是需要配置權限的,使 得程序能訪問程序所在目錄。

程序還創建一個XmlDocument對象,調用它的LoadXml方 法來加載剛剛生成的XML字符串,然後執行XSLT轉換,轉換結果就當作HTML代碼准備顯示了。

最後程序根據生成的HTML代碼設置到一個標簽控件中。

代碼中還定義了一個 GetXMLString函數,該函數能將一個對象序列化成一個帶縮進的XML字符串。其內部使用了 XmlSerializer對象。使用XmlSerializer對象能很方便的將對象的公開屬性導出為XML文檔。

/// <summary>
/// 將指定對象序列化成XML文檔,然後返回獲得 的XML字符串
/// </summary>
/// <param name="obj"> 對象</param>
/// <returns>XML字符串</returns>
private string GetXMLString( object obj )
{
  System.IO.StringWriter myStr = new System.IO.StringWriter();
  System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter( myStr );
  writer.Indentation = 3 ;
   writer.IndentChar = ' ';
  writer.Formatting = System.Xml.Formatting.Indented ;
  System.Xml.Serialization.XmlSerializer sc =
    new System.Xml.Serialization.XmlSerializer( obj.GetType() );
  sc.Serialize( writer , obj );
  writer.Close();
  string xml = myStr.ToString();
  int index = xml.IndexOf("?>");
   if( index > 0 )
    xml = xml.Substring( index + 2 );
   return xml.Trim() ;
}

DataBaseInfo.cs

本代碼生成器包括了 DataBaseInfo.cs文件,其中就是比較底層的描述數據庫表結構和字段設計信息的對象。這個 文件中定義了多個類型,其中DataBaseInfo表示一個數據庫,TableInfo表示數據表設計信息 可,FieldInfo表示數據庫字段設計信息。這三個類型構成了一個數據庫-數據表-字段的三層 對象樹狀結構。TableInfo和FieldInfo的代碼不復雜。現在說一下DataBaseInfo類型中的一 些代碼。

首先看看LoadFromPDMXMLFile和LoadFromPDMXMLDocument函數,這個函數能 分析PDM格式的XML文檔,找出其中的數據表和字段設計信息並填充到內部結構中。某些版本 的PowerDesigner生成的PDM文件是XML格式的,這方便其他程序能加載其中的數據結構設計信 息。關於這個函數詳細的處理過程,大家可以參考一個PDM的文件仔細分析。

/// <summary>
/// 從PDM數據結構定義XML文件中加載數據結構 信息
/// </summary>
/// <param name="doc">XML文檔 對象</param>
/// <returns>加載的字段信息個數</returns>
public int LoadFromPDMXMLDocument( XmlDocument doc )
{
   intFillStyle = FillStyleConst.PDM ;
  int RecordCount = 0 ;
   myTables.Clear();
  XmlNamespaceManager nsm = new XmlNamespaceManager( doc.NameTable );
  nsm.AddNamespace( "a" , "attribute" );
  nsm.AddNamespace( "c" , "collection" );
   nsm.AddNamespace( "o" , "object");
  XmlNode RootNode = doc.SelectSingleNode("/Model/o:RootObject/c:Children/o:Model" , nsm );
  if( RootNode == null )
    return 0 ;
  strName = ReadXMLValue( RootNode , "a:Name" , nsm );
  strDescription = strName ;
  // 數據表
  foreach( XmlNode TableNode in RootNode.SelectNodes("c:Tables/o:Table" , nsm ))
  {
     TableInfo table = new TableInfo();
    myTables.Add( table );
     table.Name = ReadXMLValue( TableNode , "a:Code" , nsm );
     table.Remark = ReadXMLValue( TableNode , "a:Name" , nsm );
    string keyid = ReadXMLValue( TableNode , "c:PrimaryKey/o:Key/@Ref" , nsm );
     System.Collections.Specialized.StringCollection Keys =
      new System.Collections.Specialized.StringCollection();
    if( keyid != null )
    {
      foreach( XmlNode KeyNode in TableNode.SelectNodes(
        "c:Keys/o:Key[@Id = '" + keyid + "']/c:Key.Columns/o:Column/@Ref" , nsm ))
       {
        Keys.Add( KeyNode.Value );
      }
     }
    foreach( XmlNode FieldNode in TableNode.SelectNodes ("c:Columns/o:Column" , nsm ))
    {
       RecordCount ++ ;
      string id = ( ( XmlElement )  FieldNode).GetAttribute("Id");
      FieldInfo field = new FieldInfo();
      table.Fields.Add( field );
       field.Name = ReadXMLValue( FieldNode , "a:Code" , nsm );
       field.Remark = ReadXMLValue( FieldNode , "a:Name" , nsm );
       field.Description = ReadXMLValue( FieldNode , "a:Comment" , nsm );
      string FieldType = ReadXMLValue( FieldNode , "a:DataType" , nsm );
      if( FieldType != null )
       {
        int index = FieldType.IndexOf("(");
        if( index > 0 )
          FieldType = FieldType.Substring( 0 , index );
      }
       field.FieldType = FieldType ;
      field.FieldWidth = ReadXMLValue( FieldNode , "a:Length" , nsm );
      if( Keys.Contains( id ))
        field.PrimaryKey = true;
    }
  }
  return RecordCount ;
}
private string ReadXMLValue(
   System.Xml.XmlNode node ,
  string path ,
   System.Xml.XmlNamespaceManager nsm )
{
  System.Xml.XmlNode node2 = node.SelectSingleNode( path , nsm );
  if( node2 == null )
     return null ;
  else
  {
    if( node2 is System.Xml.XmlElement )
      return ( ( System.Xml.XmlElement ) node2).InnerText ;
    else
      return node2.Value ;
  }
}

LoadFromAccess2000函數能從一個Access2000格式的數據庫中 加載數據結構設計信息。這個函數內部使用了OleDbConnection對象的GetOleDbSchemaTable 方法可以獲得數據庫的一些信息,具體什麼樣式可以參考MSND中關於GetOleDbSchema方法的 詳細說明。對於不同的數據庫其處理過程是不同的,在這裡的使用方法是我經過反復測試得 到的,而且只適用於Access2000數據庫。在這裡首先是獲得所有的數據表名和字段設計信息 ,然後獲得字段索引信息。

/// <summary>
/// 從 Jet40( Access2000 ) 的數據庫中加載數據結構信息
/// </summary>
/// <param name="myConn">數據庫連接對象</param>
/// <returns>加載的字段信息個數</returns>
public int LoadFromAccess2000( OleDbConnection myConn )
{
  intFillStyle = FillStyleConst.Access2000 ;
  int RecordCount = 0 ;
   myTables.Clear();
  string dbName = myConn.DataSource ;
  if( dbName != null )
    strName = System.IO.Path.GetFileName( dbName );
  using(System.Data.DataTable myDataTable =
         myConn.GetOleDbSchemaTable( System.Data.OleDb.OleDbSchemaGuid.Columns , null))
  {
    foreach( System.Data.DataRow myRow in myDataTable.Rows )
    {
      string strTable = Convert.ToString( myRow ["TABLE_NAME"] );
      if( ! strTable.StartsWith ("MSys"))
      {
        TableInfo myTable = myTables[ strTable ] ;
        if( myTable == null )
         {
          myTable = new TableInfo();
           myTable.Name = strTable ;
          myTables.Add( myTable );
        }
        FieldInfo myField = new FieldInfo ();
        myTable.Fields.Add( myField );
         myField.Name = Convert.ToString( myRow["COLUMN_NAME"]);
         myField.Nullable = Convert.ToBoolean( myRow["IS_NULLABLE"]);
        System.Data.OleDb.OleDbType intType = (System.Data.OleDb.OleDbType)
          Convert.ToInt32( myRow ["DATA_TYPE"]);
        if( System.DBNull.Value.Equals( myRow["DESCRIPTION"] ) == false )
        {
           myField.Remark = Convert.ToString( myRow["DESCRIPTION"] ) ;
        }
        if( intType == System.Data.OleDb.OleDbType.WChar )
        {
           myField.FieldType = "Char" ;
        }
         else
        {
          myField.FieldType = intType.ToString();
        }
         myField.FieldWidth = Convert.ToString( myRow ["CHARACTER_MAXIMUM_LENGTH"]);
        RecordCount ++ ;
      }
    }//foreach
  }//using
  using( System.Data.DataTable myDataTable =
         myConn.GetOleDbSchemaTable( System.Data.OleDb.OleDbSchemaGuid.Indexes , null))
  {
    foreach( System.Data.DataRow myRow in myDataTable.Rows )
    {
      string strTable = Convert.ToString( myRow ["TABLE_NAME"] );
      TableInfo myTable = myTables[ strTable ];
      if( myTable != null )
      {
         FieldInfo myField = myTable.Fields[ Convert.ToString( myRow ["COLUMN_NAME"])];
        if( myField != null)
         {
          myField.Indexed = true;
           myField.PrimaryKey = ( Convert.ToBoolean( myRow ["PRIMARY_KEY"]));
        }
      }
     }//foreach
  }//using
  return RecordCount ;
}//public int LoadFromAccess2000( OleDbConnection myConn )

LoadFromOracle函數用於 分析Oracle數據庫而獲得表結構和字段設計信息。其代碼如下。

在ORACLE數據庫中, 有一個名為COL的系統預定義視圖,裡面就是各個數據表名和字段定義信息,還有一個名為 user_ind_columns的預定義視圖,裡面就保存著字段索引信息。

我們首先查詢遍歷 COL視圖,獲得該視圖中保存的數據表名,字段名,字段數據類型,字段長度等信息。建立起 基本的表和字段信息結構,然後查詢遍歷user_ind_columns視圖,獲得其關鍵字段信息。

/// <summary>
/// 從 Oracle 加載數據庫結構信息
/// </summary>
/// <param name="myConn">數據庫連接對象 </param>
/// <returns>加載的字段信息個數</returns>
public int LoadFromOracle( IDbConnection myConn )
{
  intFillStyle = FillStyleConst.Oracle ;
  int RecordCount = 0 ;
  string strSQL = null;
  strSQL = "Select TName,CName,coltype,width From Col Order by TName,CName";
  myTables.Clear();
  if( myConn is OleDbConnection )
  {
    strName = ( ( System.Data.OleDb.OleDbConnection ) myConn ).DataSource
      + " - " + myConn.Database ;
  }
  else
    strName = myConn.Database ;
  using( System.Data.IDbCommand myCmd = myConn.CreateCommand())
  {
    myCmd.CommandText = strSQL ;
    IDataReader myReader = myCmd.ExecuteReader( CommandBehavior.SingleResult );
    TableInfo LastTable = null;
     while( myReader.Read())
    {
      string TableName = myReader.GetString(0).Trim();
      if( LastTable == null || LastTable.Name != TableName )
      {
        LastTable = new TableInfo();
        myTables.Add( LastTable );
         LastTable.Name = TableName ;
      }
      FieldInfo NewField = new FieldInfo();
      LastTable.Fields.Add( NewField );
      NewField.Name = myReader.GetString(1);
       NewField.FieldType = myReader.GetString(2);
      NewField.FieldWidth = myReader[3].ToString();
      RecordCount ++ ;
     }//while
    myReader.Close();
    myCmd.CommandText = @"
select table_name ,
  column_name ,
  index_name
from user_ind_columns
order by table_name , column_name ";
     myReader = myCmd.ExecuteReader( CommandBehavior.SingleResult );
     TableInfo myTable = null;
    while( myReader.Read())
    {
      myTable = myTables[ myReader.GetString(0)];
      if( myTable != null )
      {
        string IDName = myReader.GetString(2);
        string FieldName = myReader.GetString(1);
        FieldInfo myField = myTable.Fields[ FieldName ];
        if( myField != null )
        {
          myField.Indexed = true ;
          if( IDName.StartsWith("PK") )
          {
             myField.PrimaryKey = true;
          }
         }
      }
    }//while
    myReader.Close ();
  }//using
  return RecordCount ;
}//public int LoadFromOracle( System.Data.IDbConnection myConn )

LoadFromSQLServer 函數用於分析一個MSSQLServer數據庫,加載其表和字段設計信息。其代碼如下。在 SQLSERVER中包含了一些系統表,比如SysObjects,SysColumns等等,裡面就存儲了系統中所 有對象的信息,比如表,字段,存儲過程,觸發器等等。我們就可以從這些系統表中查詢所 有的表和字段定義信息。SQLSERVER中還有一個名為sp_helpindex的系統預定義存儲過程,可 用來查詢指定表的索引信息。

在代碼中我們首先使用一個比較復雜的SQL語句從系統 表中查詢數據庫中所有的數據表名,字段名,字段類型和長度等信息。這裡的SQL語句是我個 人摸索的,相信大家可以寫出更好更准確的SQL語句。我們讀取查詢結果就可以構造出基本的 表和字段對象結構,然後針對每一個表對象,調用sp_helpindex存儲過程,獲得數據表中定 義的關鍵字段信息。

/// <summary>
/// 從 SQLServer 中加載數據庫結構信息
/// </summary>
/// <param name="myConn">數據庫連接對象</param>
/// <returns>加載的字段信息個數</returns>
public int LoadFromSQLServer( IDbConnection myConn )
{
intFillStyle = FillStyleConst.SQLServer ;
int RecordCount = 0 ;
if( myConn is OleDbConnection )
strName = ( ( OleDbConnection ) myConn ).DataSource ;
else if( myConn is System.Data.SqlClient.SqlConnection )
strName = ( ( System.Data.SqlClient.SqlConnection ) myConn ).DataSource ;
strName = strName + " - " + myConn.Database ;
string strSQL = null;
strSQL = @"
select
sysobjects.name ,
syscolumns.name ,
systypes.name ,
syscolumns.length ,
syscolumns.isnullable ,
sysobjects.type
from
syscolumns,
sysobjects,
systypes
where
syscolumns.id=sysobjects.id
and syscolumns.xusertype=systypes.xusertype
and (sysobjects.type='U' or sysobjects.type='V' )
and systypes.name <>'_default_'
and systypes.name<>'sysname'
order by
sysobjects.name,
syscolumns.name";
myTables.Clear();
using( System.Data.IDbCommand myCmd = myConn.CreateCommand())
{
myCmd.CommandText = strSQL ;
IDataReader myReader = myCmd.ExecuteReader( CommandBehavior.SingleResult );
TableInfo LastTable = null;
while( myReader.Read())
{
string TableName = myReader.GetString(0).Trim();
if( LastTable == null || LastTable.Name != TableName )
{
LastTable = new TableInfo();
myTables.Add( LastTable );
LastTable.Name = TableName ;
LastTable.Tag = Convert.ToString( myReader.GetValue( 5 ));
}
FieldInfo NewField = new FieldInfo();
LastTable.Fields.Add( NewField );
NewField.Name = myReader.GetString(1);
NewField.FieldType = myReader.GetString(2);
NewField.FieldWidth = myReader[3].ToString();
if( myReader.IsDBNull( 4 ) == false)
NewField.Nullable = (myReader.GetInt32(4) == 1);
RecordCount ++ ;
}//while
myReader.Close();
// 加載主鍵信息
for( int iCount = myTables.Count - 1 ; iCount >= 0 ; iCount -- )
{
TableInfo myTable = myTables[ iCount ] ;
if( string.Compare( ( string ) myTable.Tag , "U" , true ) == 0 )
{
try
{
myCmd.CommandText = "sp_helpindex \"" + myTable.Name + "\"" ;
//myCmd.CommandType = System.Data.CommandType.Text ;
myReader = myCmd.ExecuteReader( );
while( myReader.Read())
{
string strKeyName = myReader.GetString(0);
string strDesc = myReader.GetString(1);
string strFields = myReader.GetString(2);
bool bolPrimary = ( strDesc.ToLower().IndexOf("primary") >= 0 );
foreach( string strField in strFields.Split(','))
{
FieldInfo myField = myTable.Fields[ strField.Trim()];
if( myField != null)
{
myField.Indexed = true;
myField.PrimaryKey = bolPrimary ;
}
}//foreach
}//while
myReader.Close();
}
catch( Exception ext )
{
//this.List.Remove( myTable );
myTable.Name = myTable.Name + " " + ext.Message ;
}
}
}//foreach
}//using
return RecordCount ;
}//public int LoadFromSQLServer( System.Data.IDbConnection myConn )

目前 DataBaseInfo對象只能分析Access2000,SQLSERVER和Oralce數據庫,大家以後可以完善它, 使得它能分析比如DB2,MYSQL等其他數據庫類型。在未來的軟件開發過程中,若需要分析數 據庫結構的,則只要調用這個DataBaseInfo就可以了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved