代碼:/Files/zhuqil/SqlClassFactory_src.zip
介紹
這個項目,通過給出資料來源,在一個listbox中它將會列出資料來源服務上的所有的資料庫,旁邊的listbox將會列出對應資料庫中所有的資料表。然後能產生該表的實體類抽象層。產生的類名和資料表名一致。然後將生產的代碼儲存為.cs原始碼檔案。
代碼說明:
看上面的圖,你將發現這個方案套件括了一個類庫項目和一個測試的windowsform項目TestForm。TestForm包括了兩個Form,TestMain.cs 和Input.cs。Input form 用來得到資料庫伺服器的資料來源(通常是.)或者通過輸入資料庫伺服器名,使用者名稱,密碼通過驗證登陸。TestForm是受驗證控制的,當驗證通過時,它將會出現在螢幕中。否者應用程式將會自動結束。
在sqlclassfactory 類庫項目中有很多不同的類。這裡所有的類都是靜態。出發點先看Constants類。這個類包含像連接字串這類不經常變動的字串。ConnStrArgs.cs 檔案中包含一個名字為Args的靜態類 ,這個類很關鍵。因為在其他資料庫操作之前,它是必須先做。所有其他靜態類從這一類獲得伺服器的資訊。如下所示,必須先設定:
SqlClassFactory.Args.Reset();
SqlClassFactory.Args.Type = SqlClassFactory.enmConnStrType.Trusted;
SqlClassFactory.Args.DataSource = dataSource;
SqlClassFactory.Args.InitialCatalog = "master";
下一個類是Connections.cs 類。這個類有一個名字為_connection 的類型為SqlConnection的私人欄位。它包含了一個靜態方法 GetConnection().。這個方法從Constants 得到帶參數格式化的字串,再從Args 類中得到參數值。構建一個新的connection 並返回。就像你看到得一樣,每一次,這個方法將一次又一次的通過設定過的Args 調用一個新的connection 。
Commands 類僅僅是一個SqlCommand 的宿主。 commands類的CommandText 和Connection 屬性在Adapters類中設定.這些屬性在Adapters類中將像如下設定:
Commands.ListDBCmd.CommandText = Constants.ListDBStr;
Commands.ListDBCmd.Connection = Connections.GetConnection();
Adapters._serverDA = new SqlDataAdapter(Commands.ListDBCmd);
例如,這裡設定ListDBCmd command和ServerDA屬性是使用這個command一個新的SqlDataAdapter
最後一個類是Generator。這個靜態類包含一個BeginGeneration(string)的方法。這個方法像一個構造器傳遞一個字串的參數給rawClassText 。我將使用的代碼部分真正地解釋它們。
Class.txt
Class.txt包含rawClassText的一個檔案。rawClassText是用由指定的資料庫來產生資料表代理類。Class.txt 中有一些特殊的欄位<...>,這些欄位將會被匹配的屬性名稱或者類名來取代 。
代碼
public DataTable DoSelect(string SqlCommandText)
{
SqlCommand selectCommand = new SqlCommand(SqlCommandText);
selectCommand.Connection = sqlConnection;
sqlDA.SelectCommand = selectCommand;
DataTable retdt = new DataTable();
sqlDA.Fill(retdt);
return retdt;
}
這裡 你看到了"Class.txt"的DoSelect()方法。sqlDA是類的成員它在構造器中初始化。這是這個類中最簡單的方法。通過填補資料集ret,然後返回ret。
代碼
public bool DoInsert(string SqlCommandText, params object[] args)
{
SqlCommand insertCommand = new SqlCommand(SqlCommandText);
string argInCmd = null;
Regex r = new Regex(@"@(\S+)", RegexOptions.IgnoreCase);
int i = 0;
if (r.Matches(SqlCommandText).Count == args.Length)
{
foreach (object arg in args)
{
argInCmd = r.Matches(SqlCommandText)[i].ToString();
argInCmd = argInCmd.Trim().TrimEnd(new char[] {')', ','});
insertCommand.Parameters.AddWithValue(argInCmd, arg);
i++;
}
}
else
return false;
insertCommand.Connection = sqlConnection;
sqlConnection.Open();
bool ret = insertCommand.ExecuteNonQuery() > 0;
sqlConnection.Close();
return ret;
}
這裡你看到"Class.txt"的DoInsert()方法。這種方法比較複雜。它這樣被使用:DoInsert("Insert into Employees (firstname, lastname) values (@fname, @lname)", "Ozgur", "Sonmez"); 這是所有項目的最聰明的方法。這需要params類型的參數args。args包含了所有添加到sqlcommand的參數。在上面的例子中字串argInCmd中'@fname' 是第一參數,@lname是第二個參數。 argInCmd將用來進行輪轉參數匹配。
new Regex(@"@(\S+)", RegexOptions.IgnoreCase); 是用來匹配'@matched_parameter'。這是後採取<r.Matches(SqlCommandText)[i].ToString();>。對於有些原因我無法找到使C#完全的匹配,因此會得到 '@lname)' 或者 '@fname,' 所有我需要做一些裁剪的工作。完全符合的字元將會儲存在argInCmd中,通過Parameter.AddWithValue()方法將它添加到sqlcommand的參數中,然後開啟串連connection,執行ExecuteNonQuery。
使用代碼:
這個程式碼封裝含了一個類庫項目和一個test form的windowsform項目。為簡潔起見,我通過使用SqlClassFactory dll來將兩個分開的listbox 控制項來顯示資料庫和關係資料表。類庫項目產生SqlClassFactory.dll ,主入口是TestForm.exe。你能在任何地方使用這個SqlClassFactory.dll類庫,都能得到兩份名單。但這不是SqlClassLibrary僅有的工作。它也包含了通用的Generator類。這個類裡麵包含了public static void BeginGeneration(string rawText)。這個方法從 Class.txt中得到rawText字串,用適當的名字替換所有的<...>。這裡給出Class.txt的部分作為例子:
namespace <database_name>
{ public class <table_name>
{ <column_name>
SqlDataAdapter sqlDA = null;
SqlConnection sqlConnection = null;
下面是TestForm應用程式的核心:
代碼
SqlClassFactory.Generator.BeginGeneration(rtxtClass.Text);
SqlClassFactory.Generator.AddTableDBName(tableName, dbName);
foreach (DataRow row in dtColumns.Rows)
{
SqlClassFactory.Generator.AddField
(row["DATA_TYPE"].ToString(), row["COLUMN_NAME"].ToString());
}
SqlClassFactory.Generator.EndGeneration();
rtxtClass.Text = SqlClassFactory.Generator.RawClassText;
這裡靜態方法BeginGenerator()從richtextbox rtxtClass中擷取文本資料,它在SqlClassFactory.Generator類的內部。然後在rtxtClass.Text中Generator.AddTableDBName(..)用適合的字元替換"<database_name>" 和"<table_name>" 。接著一個foreach 迴圈中每次都執行Generator中的靜態方法AddField(),這用來屬性名稱,原類的字串來自Class.txt。這個方法用屬性名稱取代"<column_name>" 。也就是在給定的資料庫表的列名。你可以從上面給出的參數:row["DATA_TYPE"].ToString(),
row["COLUMN_NAME"].ToString()。
這個功能值得關注。在這個功能有行的關鍵代碼如下:
代碼
string fieldText =
String.Format("public {0} {1}", propertyType, propertyName)
+ " { get; set; }\n\t\t\t<column_name>";
RawClassText = RawClassText.Replace("<column_name>", fieldText);
這裡,每次調用AddField(),fieldtext 被設定成類似"public int productId { get; set; }"的字串,首先取代屬性的類型,然後取代屬性的名字。接著設定為下次調用AddField()時使用的column_name ,首先為的屬性名稱增加一新行,然後增加一行"<column_name>" 。
SqlClassFactory.Generator.EndGeneration();
這行代碼使得String.Empty替換"<column_name>",清除多餘的部分。
rtxtClass.Text = SqlClassFactory.Generator.RawClassText;
希望這篇文章對想寫自己的代碼產生器的朋友有所協助(紅色譯者加)
原文:http://www.codeproject.com/KB/database/SqlClassFactoryLibrary.aspx