- 思來想去用T4生成代碼要學習它的語法,C#本身能很簡單地生成txt文件,為啥不直接批量替換模板方式自己寫個的三層代碼生成器。說干就干,2個小時搞定。當然各層還可以做的更精細,比如
DAL層
的Add
方法Insert、Update
語句中主鍵就不該出現等。但是大體上是能使用了。另外,生成的代碼格式有些地方不規整,但是編譯不出錯,我們可以在實現具體類時借助vs
格式化功能(快捷鍵ctrl+E+D
)來使其規整或調模板。
- 生成類文件整體思路:定模板,設置替換點,取得數據庫中所有表及字段,遍歷替換,輸出cs文件。類文件模板是根據自己項目代碼實踐而定。
- 具體算法:
1、讀取數據庫中所有表及字段,返回DBInfo(Dictionary<{表,說明},Dictionary<{字段,說明},數據類型>>)
2、遍歷DBInfo,生成Model層代碼
3、遍歷DBInfo,生成DAL層代碼
4、遍歷DBInfo,生成BLL層代碼
- 代碼說明:我是在現有舊項目中建的一個
test.aspx
中實現的,其中DbHelperSQL
是數據庫幫助類(網上可以隨意找到),運行本代碼前最好是先搭建的解決方案能訪問DB了,再運行本代碼,因為代碼要連接項目DB,獲得所有表及其字段以便批量生產三層文件。代碼中用到的三層模板是我根據Dapper使用經驗而確定的,大家可以替換成自己的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using System.IO;
public partial class test : System.Web.UI.Page
{
/***
* ○ 生成類文件整體思路:定模板,設置替換點,遍歷DBInfo替換,輸出cs文件。類文件模板是根據自己項目代碼實踐而定。
* ○ 具體算法:
* 1、讀取數據庫中所有表及字段,返回DBInfo(Dictionary<{表,說明},Dictionary<{字段,說明},數據類型>>)
* 2、遍歷DBInfo,生成Model層代碼
* 3、遍歷DBInfo,生成DAL層代碼
* 4、遍歷DBInfo,生成BLL層代碼
***/
protected void Page_Load(object sender, EventArgs e)
{
Dictionary<string, Dictionary<string, string>> r = GetDBInfo();
ModelFactory(r);
DALFactory(r);
BLLFactory(r);
Response.Write(r.Count);
}
#region 生成三層代碼
#region 全局變量
static string DalNameSpace = "CMS.DAL";//DAL層命名空間(下同)
static string ModelNameSpace = "CMS.Model";
static string BllNameSpace = "CMS.BLL";
static string DalLayerPath = @"d:\Test\DAL\";//dal層代碼生成代碼文件存放路徑(下同)
static string ModelLayerPath = @"d:\Test\Model\";
static string BllLayerPath = @"d:\Test\BLL\";
static char DicSplit = '≡';//分隔符,注意:代碼不是因此出錯,建議不要修改
#endregion
#region 得到數據庫中所有表及字段
private static Dictionary<string, Dictionary<string, string>> GetDBInfo()
{
//Dictionary<{表,說明},Dictionary<{字段,說明},數據類型>>
Dictionary<string, Dictionary<string, string>> dicR = new Dictionary<string, Dictionary<string, string>>();
string getTables = " SELECT name FROM sysobjects WHERE xtype = 'U' ";
DataTable dt = DbHelperSQL.Query(getTables).Tables[0];
foreach (DataRow item in dt.Rows)
{
string tblName = item[0].ToString();
//"SELECT COLUMN_NAME,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + tblName+"' ";
string getTblFields = @"SELECT
表名 = case when a.colorder=1 then d.name else '' end,
表說明 = case when a.colorder=1 then isnull(f.value,'') else '' end,
字段序號 = a.colorder,
字段名 = a.name,
標識 = case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '√'else '' end,
主鍵 = case when exists(SELECT 1 FROM sysobjects where xtype='PK' and parent_obj=a.id and name in (
SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid))) then '√' else '' end,
類型 = b.name,
占用字節數 = a.length,
長度 = COLUMNPROPERTY(a.id,a.name,'PRECISION'),
小數位數 = isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0),
允許空 = case when a.isnullable=1 then '√'else '' end,
默認值 = isnull(e.text,''),
字段說明 = isnull(g.[value],'')
FROM
syscolumns a
left join
systypes b
on
a.xusertype=b.xusertype
inner join
sysobjects d
on
a.id=d.id and d.xtype='U' and d.name<>'dtproperties'
left join
syscomments e
on
a.cdefault=e.id
left join
sys.extended_properties g
on
a.id=G.major_id and a.colid=g.minor_id
left join
sys.extended_properties f
on
d.id=f.major_id and f.minor_id=0
where d.name='" + tblName + "' order by a.id,a.colorder";
DataTable dtTbl = DbHelperSQL.Query(getTblFields).Tables[0];
Dictionary<string, string> dicItem = new Dictionary<string, string>();
foreach (DataRow tbl in dtTbl.Rows)
{
if (tbl[1].ToString() != "")
tblName += DicSplit + tbl[1].ToString();
string COLUMN_NAME = tbl[3].ToString() + DicSplit + tbl[12].ToString();
string DATA_TYPE = tbl[6].ToString();
dicItem.Add(COLUMN_NAME, DATA_TYPE);
}
dicR.Add(tblName, dicItem);
}
return dicR;
}
#endregion
#region 遍歷生成Model層代碼
private static void ModelFactory(Dictionary<string, Dictionary<string, string>> dic)
{
foreach (var item in dic)
{
#region 類模板
StringBuilder sb = new StringBuilder();
sb.Append(" using System; \r\n");
sb.Append(" using System.Text; \r\n");
sb.Append(" \r\n");
sb.Append(" /************************************************** \r\n");
sb.Append(" * 類 名 稱 : 【類名稱】 \r\n");
sb.Append(" * 版 本 號 : v1.0.0.0 \r\n");
sb.Append(" * 說 明 : 【表職責】 \r\n");
sb.Append(" * 作 者 : \r\n");
sb.Append(" * 創建時間 : 【時間戳】 \r\n");
sb.Append(" **************************************************/ \r\n");
sb.Append(" namespace 【命名空間】 \r\n");
sb.Append(" { \r\n");
sb.Append(" public class 【表】 \r\n ");
sb.Append(" { \r\n");
sb.Append(" \r\n");
sb.Append(" public 【表】() \r\n");
sb.Append(" { \r\n ");
sb.Append(" } \r\n ");
sb.Append(" 【屬性部分】 \r\n ");
sb.Append(" } \r\n ");
sb.Append(" } \r\n ");
#endregion
#region 屬性部分
StringBuilder propPart = new StringBuilder();
foreach (var field in item.Value)
{
string[] key = field.Key.Split(DicSplit);
string type = ChangeToCSharpType(field.Value.ToString());//Dictionary<{表,說明},Dictionary<{字段,說明},數據類型>>
string fName = key[0];
string fRemark = key.Length == 2 ? key[1] : "";
string first = field.Key.Substring(0, 1);//第一個字母
fName = fName.Substring(1, fName.Length - 1);//不含第一個字母
string _f = first.ToLower() + fName;
string pF = first.ToUpper() + fName;
propPart.Append(" \r\n");
propPart.AppendFormat(" private {0} {1}; \r\n", type, _f);
propPart.AppendFormat(" //{0} \r\n", fRemark);
propPart.AppendFormat(" public {0} {1} \r\n", type, pF);
propPart.Append(" { \r\n");
propPart.Append(" get { return " + _f + "; } \r\n");
propPart.Append(" set { " + _f + " = value; } \r\n");
propPart.Append(" } \r\n");
}
#endregion
string[] tableInfo = item.Key.Split(DicSplit);
string tblName = tableInfo[0];
string tblWork = tableInfo.Length == 2 ? tableInfo[1] : "";
string r = sb.ToString()
.Replace("【類名稱】", tblName + "表實體類")
.Replace("【時間戳】", DateTime.Now.ToString())
.Replace("【命名空間】", ModelNameSpace)
.Replace("【表】", tblName)
.Replace("【表職責】", tblWork)
.Replace("【屬性部分】", propPart.ToString());
CreateTxt(ModelLayerPath + tblName + "Model.cs", ModelLayerPath, r);
}
}
#endregion
#region 遍歷生成DAL層代碼
private static void DALFactory(Dictionary<string, Dictionary<string, string>> dic)
{
foreach (var item in dic)
{
StringBuilder sb = new StringBuilder();
#region 類模板
sb.Append("using System.Collections.Generic; \r\n");
sb.Append("using System.Text; \r\n ");
sb.Append(" \r\n ");
sb.Append("/************************************************** \r\n ");
sb.Append(" * 類 名 稱 : 【類名稱】 \r\n ");
sb.Append(" * 版 本 號 : v1.0.0.0 \r\n ");
sb.Append(" * 說 明 : 用於【表】數據持久化 \r\n ");
sb.Append(" * 作 者 : \r\n ");
sb.Append(" * 創建時間 : 【時間戳】 \r\n");
sb.Append("****************************************************/ \r\n ");
sb.Append("namespace 【命名空間】 \r\n ");
sb.Append("{ \r\n ");
sb.Append(" public class 【表】DAL \r\n ");
sb.Append(" { \r\n ");
sb.Append(" #region select \r\n ");
sb.Append(" \r\n ");
sb.Append(" public List<【表】> Select(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" string sql = \"SELECT * FROM 【表】 where \"; \r\n ");
sb.Append(" return DapperHelper.Select<【表】>(sql, model); \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region delete \r\n ");
sb.Append(" public bool Delete(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" string sql = \"DELETE FROM 【表】 WHERE Id=@Id\"; \r\n");
sb.Append(" return DapperHelper.NoQuery<【表】>(sql, model) > 0; \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region insert \r\n ");
sb.Append(" public bool Add(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" 【當前表Insert】 \r\n ");
sb.Append(" return DapperHelper.NoQuery<【表】>(sql.ToString(), model) > 0; \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region update \r\n ");
sb.Append(" public bool Update(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" 【當前表Update】 \r\n ");
sb.Append(" return DapperHelper.NoQuery<【表】>(sql, model) > 0; \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" } \r\n ");
sb.Append("} \r\n ");
#endregion
string tblName = item.Key.Split(DicSplit)[0];
string insetSQL = GetInsertSQL(tblName, item.Value);
string updateSQL = GetUpdateSQL(tblName, item.Value);
string r = sb.ToString()
.Replace("【類名稱】", tblName + "表DAL類")
.Replace("【時間戳】", DateTime.Now.ToString())
.Replace("【命名空間】", DalNameSpace)
.Replace("【表】", tblName)
.Replace("【當前表Insert】", insetSQL)
.Replace("【當前表Update】", updateSQL);
CreateTxt(DalLayerPath + tblName + "DAL.cs", DalLayerPath, r);
}
}
#endregion
#region 遍歷生成BLL層代碼
private static void BLLFactory(Dictionary<string, Dictionary<string, string>> dic)
{
foreach (var item in dic)
{
StringBuilder sb = new StringBuilder();
#region 類模板
sb.Append("using System; \r\n");
sb.Append("using System.Collections.Generic; \r\n");
sb.Append("using System.Linq; \r\n");
sb.Append("using System.Text; \r\n");
sb.Append("using System.Threading.Tasks; \r\n");
sb.Append(" \r\n ");
sb.Append("/************************************************** \r\n ");
sb.Append(" * 類 名 稱 : 【類名稱】 \r\n ");
sb.Append(" * 版 本 號 : v1.0.0.0 \r\n ");
sb.Append(" * 說 明 : 用於【表】表業務操作 \r\n ");
sb.Append(" * 作 者 : \r\n ");
sb.Append(" * 創建時間 : 【時間戳】 \r\n");
sb.Append("****************************************************/ \r\n ");
sb.Append("namespace 【命名空間】 \r\n ");
sb.Append("{ \r\n ");
sb.Append(" public class 【表】BLL \r\n ");
sb.Append(" { \r\n ");
sb.Append(" #region select \r\n ");
sb.Append(" \r\n ");
sb.Append(" public List<【表】> Select(【表】 model, string sqlWhere) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" return 【表】DAL.Select(model, sqlWhere); \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region delete \r\n ");
sb.Append(" public bool Delete(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" return 【表】DAL.Delete(model); \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region insert \r\n ");
sb.Append(" public bool Add(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" return 【表】DAL.Add(model); \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" \r\n ");
sb.Append(" #region update \r\n ");
sb.Append(" public bool Update(【表】 model) \r\n ");
sb.Append(" { \r\n ");
sb.Append(" return 【表】DAL.Update(model); \r\n ");
sb.Append(" } \r\n ");
sb.Append(" #endregion \r\n ");
sb.Append(" } \r\n ");
sb.Append("} \r\n ");
#endregion
string tblName = item.Key.Split(DicSplit)[0];
string r = sb.ToString()
.Replace("【類名稱】", tblName + "表BLL類")
.Replace("【時間戳】", DateTime.Now.ToString())
.Replace("【命名空間】", BllNameSpace)
.Replace("【表】", tblName);
CreateTxt(BllLayerPath + tblName + "BLL.cs", BllLayerPath, r);
}
}
#endregion
#region 其他
//為某個表生成insert語句
public static string GetInsertSQL(string tableName, Dictionary<string, string> filedDic)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("StringBuilder sql = new StringBuilder(); \r\n");
sb.AppendFormat(" #region sql \r\n");
sb.AppendFormat(" sql.Append(\"INSERT INTO {0} \"); \r\n", tableName);
sb.AppendFormat(" sql.Append(\" ( \"); \r\n");
int i = 0;
foreach (var item in filedDic)
{
string[] key = item.Key.Split(DicSplit);
string filedName = key[0];
string splitChar = ",";
if (i + 1 == filedDic.Count)
splitChar = "";
sb.AppendFormat(" sql.Append(\" {0} {1} \"); \r\n", filedName, splitChar);
i++;
}
sb.AppendFormat(" sql.Append(\" ) \"); \r\n");
sb.AppendFormat(" sql.Append(\" VALUES ( \"); \r\n");
int b = 0;
foreach (var item in filedDic)
{
string[] key = item.Key.Split(DicSplit);
string filedName = key[0];
string splitChar = ",";
if (b + 1 == filedDic.Count)
splitChar = "";
sb.AppendFormat(" sql.Append(\" @{0} {1} \"); \r\n", filedName, splitChar);
b++;
}
sb.AppendFormat(" sql.Append(\" ) \"); \r\n");
sb.AppendFormat(" #endregion sql \r\n");
return sb.ToString();
}
//為某個表生成update語句
public static string GetUpdateSQL(string tableName, Dictionary<string, string> filedDic)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("StringBuilder sql = new StringBuilder(); \r\n");
sb.AppendFormat(" #region sql \r\n");
sb.AppendFormat(" sql.Append(\" Update {0} set \"); \r\n", tableName);
int i = 0;
foreach (var item in filedDic)
{
string[] key = item.Key.Split(DicSplit);
string filedName = key[0];
string splitChar = ",";
if (i + 1 == filedDic.Count)
splitChar = "";
sb.AppendFormat(" sql.Append(\" {0}=@{0} {1} \"); \r\n", filedName, splitChar);
i++;
}
sb.AppendFormat(" sql.Append(\" Where Id=@Id \"); \r\n");
sb.AppendFormat(" #endregion sql \r\n");
return sb.ToString();
}
//生成cs文件
public static void CreateTxt(string filePath, string folderPath, string fileContent)
{
if (!Directory.Exists(folderPath))//如果不存在就創建文件夾
Directory.CreateDirectory(folderPath);
FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
sw.Write(fileContent);
sw.Close();
fs.Close();
}
// 數據庫中與C#中的數據類型對照
private static string ChangeToCSharpType(string type)
{
string reval = string.Empty;
switch (type.ToLower())
{
case "int":
reval = "int";
break;
case "text":
reval = "string";
break;
case "bigint":
reval = "int";
break;
case "binary":
reval = "byte[]";
break;
case "bit":
reval = "bool";
break;
case "char":
reval = "string";
break;
case "datetime":
reval = "DateTime";
break;
case "decimal":
reval = "decimal";
break;
case "float":
reval = "double";
break;
case "image":
reval = "byte[]";
break;
case "money":
reval = "decimal";
break;
case "nchar":
reval = "string";
break;
case "ntext":
reval = "string";
break;
case "numeric":
reval = "decimal";
break;
case "nvarchar":
reval = "string";
break;
case "real":
reval = "single";
break;
case "smalldatetime":
reval = "DateTime";
break;
case "smallint":
reval = "int";
break;
case "smallmoney":
reval = "decimal";
break;
case "timestamp":
reval = "DateTime";
break;
case "tinyint":
reval = "byte";
break;
case "uniqueidentifier":
reval = "System.Guid";
break;
case "varbinary":
reval = "byte[]";
break;
case "varchar":
reval = "string";
break;
case "Variant":
reval = "Object";
break;
default:
reval = "string";
break;
}
return reval;
}
#endregion
#endregion
}