完整教程链接:ASP.Net: EshineASPNet-基于ASP.Net敏捷开发开源框架
本教程介绍一套自主开发的项目实现自动生成代码,以及使用codesmith自动生成代码。
首先要讲的是在一个项目里面,很多代码是有共性的,比如数据库表要对应类,增删改查的方法,这些都是公用的必须有的,做这个算没有创意的体力活,堆代码,这种就最适合用自动生成了。
然后是三层架构,这是一个比较老的话题了,也能搜到很多文章,因为这里用到了就提一下。数据库每一个表对应一个Model,对这个Model的数据库操作放进SQLServerDAL,接口提取到IDAL,最后就可以在上面封装业务逻辑成Bll了,这里也加了DALFactory这个用来预留个更换数据库的可能。那么一旦一个数据库表定义好以后,这几个类的代码其实都是可以初始化生成一次的,最后只是在Bll里面添加更多的函数就可以了。虽说老或者不好,也就是说有Linq更新的查询方式,和主要用于Webform而不是MVC。不过数据库执行效率是比Linq要高的,对sql的磨练是好的,对分层的理解是需要的。
本框架包含了一个Windows应用,在csswrap文件夹,用来实现根据数据表信息自动生成从Model到Bll的所有代码并保存文件至对应文件夹。懒人有懒方法,直接假设表的第一个字段是自增id,设成主键和标识。右击Sql Server数据库的表-编辑表脚本为(S)-CREAT到(C)-新建编辑器窗口,复制从CREATE TABLE行到字段最后一行(即CONSTRAINT的上面一行),例如
CREATE TABLE [dbo].[province](
[id] [int] IDENTITY(1,1) NOT NULL,
[code] [nvarchar](6) NULL,
[name] [nvarchar](40) NULL,
这里就包含了表名,字段名和字段类型,我们根据这些信息自动生成对应的Model,DAL,Bll等。做到这一点其实就是用StringBuilder不断Append就好了。
private void button2_Click(object sender, EventArgs e)
{
if(! getfolderpath()) return;
//[customerName] [varchar](50) NULL,
Regex r = new Regex(@"\[\w*\]");
Match mch = Regex.Match(this.richTextBox3.Lines[0], @"dbo\]\.\[(?<tname>\w+)\]");
string tname = mch.Groups["tname"].Value;//table name
mch = Regex.Match(this.richTextBox3.Lines[1], @"\[(?<idname>\w+)\]");
string idname=mch.Groups["idname"].Value;
string s1, s2;
StringBuilder sb1 = new StringBuilder();//model前部分
StringBuilder sb2 = new StringBuilder();//model后部分
StringBuilder sb3 = new StringBuilder();//sqlServerDal
StringBuilder sb4 = new StringBuilder();//sqlServerDal
StringBuilder sb5 = new StringBuilder();//sqlServerDal
StringBuilder sb6 = new StringBuilder();//sqlServerDal
StringBuilder sb7 = new StringBuilder();//interface
StringBuilder sb8 = new StringBuilder();//bll
StringBuilder sb9 = new StringBuilder();//sqlServerDal
StringBuilder sb10 = new StringBuilder();//DALFactory
sb1.Append("using System;\n\n");
sb1.Append("namespace Model\n{\n");
sb1.Append("public class " + tname + "\n{\n");
sb1.Append("private int _" + idname + " = 0;\n");
sb2.Append("public int " + idname + "{get { return _" + idname + "; }\n\tset { _" + idname + " = value; }}\n\n");
sb3.Append("using System;\n");
sb3.Append("using System.Text;\n");
sb3.Append("using System.Data;\n\n");
sb3.Append("namespace SQLServerDAL\n{\n");
sb3.Append("public class sql_" + tname + ":IDAL." + tname + "Dal\n{\n");
sb3.Append("DBunit.SQLAccess sql = new DBunit.SQLAccess();\n");
sb3.Append("DateTime baddate = DateTime.Parse(\"1900-01-01\");\n");
sb3.Append("public int Add(Model."+tname+" "+tname+")\n{\n");
sb3.Append("StringBuilder strsql = new StringBuilder();\n");
sb3.Append("strsql.Append(\"insert into " + tname + " values (\");\n");
sb4.Append("public Model." + tname + " get" + tname + "(DataTable dt)\n{\n");
sb4.Append("Model." + tname + " " + tname + " = new Model." + tname + "();\n");
sb4.Append(tname + "." + idname + " = int.Parse( dt.Rows[0][\"" + idname + "\"].ToString());\n");
sb7.Append("using System.Data;\n\n");
sb7.Append("namespace IDAL\n{\n");
sb7.Append("public interface " + tname + "Dal\n{\n");
sb7.Append("int Add(Model." + tname + " " + tname + ");\n");
sb8.Append("using System.Data;\n\n");
sb8.Append("namespace Bll\n{\n");
sb8.Append("public class " + tname + "Bll\n{\n");
sb8.Append("IDAL." + tname + "Dal itu = DALFactory." + tname + "_Factory.Createusers();\n");
sb8.Append("public int Add(Model." + tname + " " + tname + ")\n{\n");
sb8.Append("return itu.Add(" + tname + ");\n}\n");
sb9.Append("public Model." + tname + " get" + tname + "(int id)\n{\n");
sb9.Append("StringBuilder strsql = new StringBuilder();\n");
sb9.Append("strsql.Append(\"select * from " + tname + " where \");\n");
sb9.Append("strsql.AppendFormat(\"" + idname + "='{0}'\", id);\n");
sb9.Append("DataTable dt = sql.ExecuteDataSet(strsql.ToString()).Tables[0];\n");
sb9.Append("if (dt.Rows.Count < 1) return null;\n\n");
sb9.Append("return get" + tname + "(dt);\n}\n");
sb7.Append("Model." + tname + " get" + tname + "(int id);\n");
sb7.Append("Model." + tname + " get" + tname + "(DataTable dt);\n");
sb8.Append("public Model." + tname + " get" + tname + "(int id)\n{\n");
sb8.Append("return itu.get" + tname + "(id);\n}\n");
sb8.Append("public Model." + tname + " get" + tname + "(DataTable dt)\n{\n");
sb8.Append("return itu.get" + tname + "(dt);\n}\n");
sb5.Append("public int update(Model." + tname + " " + tname + ")\n{\n");
sb5.Append("StringBuilder strsql = new StringBuilder();\n");
sb5.Append("strsql.Append(\"update " + tname + " set \");\n");
sb7.Append("int update(Model." + tname + " " + tname + ");\n");
sb8.Append("public int update(Model." + tname + " " + tname + ")\n{\n");
sb8.Append("return itu.update(" + tname + ");\n}\n");
sb10.Append("using System.Reflection;\n\n");
sb10.Append("namespace DALFactory\n{\n");
sb10.Append("public class " + tname + "_Factory\n{\n");
sb10.Append("static readonly string path = System.Configuration.ConfigurationManager.AppSettings[\"DAL\"];\n");
sb10.Append("public static IDAL." + tname + "Dal Createusers()\n{\n");
sb10.Append("string classname = path + \".sql_" + tname + "\";\n");
sb10.Append("return (IDAL." + tname + "Dal)Assembly.Load(path).CreateInstance(classname);\n}\n");
sb10.Append("}\n}");
for (int i = 2; i < this.richTextBox3.Lines.Length; i++)//0行是表名,1行是id
{
if (this.richTextBox3.Lines[i].Contains("] ["))
{
s1 = r.Matches(this.richTextBox3.Lines[i])[0].ToString();
s1 = s1.Substring(1, s1.Length - 2);
s2 = r.Matches(this.richTextBox3.Lines[i])[1].ToString();
s2 = s2.Substring(1, s2.Length - 2);
switch (s2)
{
case "varchar": sb1.Append("private string _" + s1 + " = \"\";\n");
sb2.Append("public string " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"'{0}',\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = dt.Rows[0][\"" + s1 + "\"].ToString();\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ='{0}',\", " + tname + "." + s1 + ");\n");
break;
case "nvarchar": sb1.Append("private string _" + s1 + " = \"\";\n");
sb2.Append("public string " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"N'{0}',\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = dt.Rows[0][\"" + s1 + "\"].ToString();\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " =N'{0}',\", " + tname + "." + s1 + ");\n");
break;
case "text": sb1.Append("private string _" + s1 + " = \"\";\n");
sb2.Append("public string " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"'{0}',\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = dt.Rows[0][\"" + s1 + "\"].ToString();\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ='{0}',\", " + tname + "." + s1 + ");\n");
break;
case "datetime": sb1.Append("private DateTime _" + s1 + "= DateTime.Parse(\"1900-01-01\");\n");
sb2.Append("public DateTime " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"{0},\", " + tname + "." + s1 + " == baddate ? \"null\" :\"'\" + " + tname + "." + s1 + ".ToString() +\"'\");\n");
sb4.Append(tname + "." + s1 + " = dt.Rows[0][\"" + s1 + "\"].ToString() == \"\" ? baddate : DateTime.Parse(dt.Rows[0][\"" + s1 + "\"].ToString());\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ={0},\", " + tname + "." + s1 + " == baddate ? \"null\" :\"'\" + " + tname + "." + s1 + ".ToString() +\"'\");\n");
break;
case "int": sb1.Append("private int _" + s1 + " = 0;\n");
sb2.Append("public int " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"{0},\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = int.Parse( dt.Rows[0][\"" + s1 + "\"].ToString());\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ='{0}',\", " + tname + "." + s1 + ");\n");
break;
case "decimal": sb1.Append("private decimal _" + s1 + " = 0M;\n");
sb2.Append("public decimal " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"{0},\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = decimal.Parse( dt.Rows[0][\"" + s1 + "\"].ToString());\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ='{0}',\", " + tname + "." + s1 + ");\n");
break;
case "float": sb1.Append("private double _" + s1 + " = 0.0;\n");
sb2.Append("public double " + s1 + "{get { return _" + s1 + "; }\n\tset { _" + s1 + " = value; }}\n\n");
sb3.Append("strsql.AppendFormat(\"{0},\", " + tname + "." + s1 + ");\n");
sb4.Append(tname + "." + s1 + " = double.Parse( dt.Rows[0][\"" + s1 + "\"].ToString());\n");
sb5.Append("strsql.AppendFormat(\" " + s1 + " ='{0}',\", " + tname + "." + s1 + ");\n");
break;
default: sb1.Append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
sb2.Append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
break;
}
}
}
sb2.Append("}\n}");
sb3.Remove(sb3.ToString().LastIndexOf(",\",") , 1);
sb3.Append("strsql.Append(\") select SCOPE_IDENTITY()\");\n");
sb3.Append("return Convert.ToInt32(sql.ExecuteSc(strsql.ToString()));\n}\n");
sb4.Append("return " + tname + ";\n}\n");
sb5.Remove(sb5.ToString().LastIndexOf(",\","), 1);
sb5.Append("strsql.AppendFormat(\" where " + idname + "={0}\", " + tname + "." + idname + ");\n");
sb5.Append("return sql.ExecuteNonQuery(strsql.ToString());\n}\n");
sb6.Append("public int Delete(int " + idname + ")\n{\n");
sb6.Append("return sql.ExecuteNonQuery(\"delete from " + tname + " where " + idname + "=\" + " + idname + ");\n}\n");
sb6.Append("public DataTable Select(string ss)\n{\n");
sb6.Append("return sql.ExecuteDataSet(ss).Tables[0];\n}\n");
sb7.Append("int Delete(int " + idname + ");\n");
sb7.Append("DataTable Select(string ss);\n");
sb7.Append("}\n}");
sb8.Append("public int Delete(int " + idname + ")\n{\n");
sb8.Append("return itu.Delete(" + idname + ");\n}\n");
sb8.Append("public DataTable Select(string ss)\n{\n");
sb8.Append("return itu.Select(ss);\n}\n}\n}");
sb6.Append("}\n}");
this.richTextBox4.Text = sb1.ToString() + "\n\n" + sb2.ToString();//model
this.richTextBox7.Text = sb3.ToString() + "\n\n" + sb4.ToString() + "\n\n" + sb9.ToString() + "\n\n" + sb5.ToString() + "\n\n" + sb6.ToString();//sqlserverdal
this.richTextBox8.Text = sb7.ToString();//idal
this.richTextBox9.Text = sb8.ToString();//bll
this.richTextBox14.Text = sb10.ToString();//dalfactory
string filepath = folderpath + "\\Bll\\" + tname + "Bll.cs";
if (File.Exists(filepath))
{
FileInfo fileInfo = new FileInfo(filepath);
fileInfo.MoveTo(folderpath + "\\Bll\\" + tname + "Bll"+DateTime.Now.ToString("yyyyMMddHHmmss") +".cs");
}
File.AppendAllText(filepath, this.richTextBox9.Text.Replace("\n", "\r\n"), Encoding.Default);
filepath = folderpath + "\\Model\\" + tname + ".cs";
if (File.Exists(filepath)) File.Delete(filepath);
File.AppendAllText(filepath, this.richTextBox4.Text.Replace("\n", "\r\n"), Encoding.Default);
filepath = folderpath + "\\SQLServerDAL\\sql_" + tname + ".cs";
if (File.Exists(filepath)) File.Delete(filepath);
File.AppendAllText(filepath, this.richTextBox7.Text.Replace("\n", "\r\n"), Encoding.Default);
filepath = folderpath + "\\IDAL\\" + tname + "Dal.cs";
if (File.Exists(filepath)) File.Delete(filepath);
File.AppendAllText(filepath, this.richTextBox8.Text.Replace("\n", "\r\n"), Encoding.Default);
filepath = folderpath + "\\DALFactory\\" + tname + "_Factory.cs";
if (File.Exists(filepath)) File.Delete(filepath);
File.AppendAllText(filepath, this.richTextBox14.Text.Replace("\n", "\r\n"), Encoding.Default);
}
就是这么长段的Append最终得到了我们需要的文件,最后在每个项目里面添加现有项就可以使用了。这是Windows应用所以要去Debug文件夹运行这个exe程序。
除了自己写,也可以使用工具,比如CodeSmith,这里给一个生成Entity的样例,选择数据库的表以后就会执行并生成文件。
<%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" ResponseEncoding="UTF-8" Inherits="" Debug="False" Description="Template description here." %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the object is based on." %>
<%--@ Property Name="ModuleName" Type="System.String" Optional="false" Category="Context" --%>
<%@ Property Name="package" Type="System.String" Optional="false" Category="Context" Default="com.test"%>
<%@ Property Name="className" Type="System.String" Optional="false" Category="Context" Default="Test"%>
<%--@ Property Name="SourceDatabase" type="SchemaExplorer.DatabaseSchema" DeepLoad="True" Optional="False" Category="01. GettingStarted - Required" Description="Database that the tables views, and storedprocedures should be based on. IMPORTANT!!! If SourceTables and SourceViews areleft blank, the Entire Database will then be generated."--%>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="System.Data" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Collections" %>
<%@ Import Namespace="CodeSmith.CustomProperties" %>
<%@ Import Namespace="System.Windows.Forms.Design" %>
<%@ Import Namespace="System.IO" %>
<script runat="template">
public string modelPackage = "entity1";
public string getColumnName(string columnName, Boolean isClass){
if(columnName == null || columnName.Equals("")){
return "";
}
int indx = columnName.IndexOf("_");
if(indx != -1){
columnName = columnName.ToLower();
string[] names = columnName.Split('_');
columnName = "";
for(int i=0;i<names.Length;i++){
if(i==0 && !isClass){
columnName += names[i].Substring(0,1).ToLower();
}else{
columnName += names[i].Substring(0,1).ToUpper();
}
columnName += names[i].Substring(1,names[i].Length - 1);
}
} else {
if(isClass){
columnName = columnName.Substring(0,1).ToUpper() + columnName.Substring(1,columnName.Length - 1);
} else {
columnName = columnName.Substring(0,1).ToLower() + columnName.Substring(1,columnName.Length - 1);
}
}
return columnName;
}
public string getTypeName(ColumnSchema column){
return column.NativeType.ToUpper();
}
public string getColumnType(ColumnSchema column){
switch (getTypeName(column)){
case "BIGINT": return "Long";
case "IMAGE":
case "REAL":
case "VARBINARY":
case "SQL_VARIANT":
case "BLOB":
case "CLOB":
case "BINARY": return "Byte[]";
case "BIT":
case "SMALLINT":
case "TINYINT": return "int";
case "FLOAT": return "float";
case "NUMBER":
case "INT": return "int";
case "DECIMAL":
case "NUMERIC":
case "MONEY": return "decimal";
case "NCHAR":
case "NTEXT":
case "NVARCHAR": return "string";
case "DATE":
case "DATETIME":
case "SMALLDATETIME": return "DateTime";
case "SMALLMONEY": return "decimal";
case "VARCHAR":
case "VARCHAR2":
case "SYSNAME":
case "CHAR":
case "TEXT": return "String";
default: return getTypeName(column);
}
}
public string getClassName(TableSchema table){
return table.Name.Replace("db_", "DB")
.Replace("rel_", "Rel")
.Replace("biz_", "Biz")
.Replace("log_", "Log")
.Replace("sys_", "Sys");
}
public string path = "d:\\test";
public string fileName = "test.txt";
public void CreateDirectory(string path){
if(!Directory.Exists(path)){
Directory.CreateDirectory(path);
} else {
//Directory.Delete(path,true);
Directory.CreateDirectory(path);
}
}
public override void Render(TextWriter tw)
{
CreateDirectory(path);
//base.Render(tw);
StreamWriter fs2 = new StreamWriter(path + "\\" + fileName,true);
this.Response.AddTextWriter(fs2);
base.Render(tw);
fs2.Close();
}
</script>
using System;
using FluentNHibernate.Mapping;
namespace <%=this.package%>.Framework.Model.Mapping
{
public class <%=getClassName(this.SourceTable)%>Map : ClassMap<<%=getClassName(this.SourceTable)%>>
{
public <%=getClassName(this.SourceTable)%>Map()
{
Table("<%=this.SourceTable%>");
Id(x => x.Id).Column("<%=getColumnName(this.SourceTable.Columns[0].Name,false) %>").GeneratedBy.Identity();
Map(x => x.CreateTime);
Map(x => x.UpdateTime);
Map(x => x.IsShow);
Map(x => x.IsDel);
<%
bool firstone=true;
foreach(ColumnSchema col in this.SourceTable.Columns)
{
string columnName = col.Name;
if(columnName != "IsDel" && columnName != "IsShow" && columnName != "CreateTime" && columnName != "UpdateTime")
{
if(firstone) {firstone=false; continue; }
%>
Map(x => x.<%=getColumnName(columnName,false) %>).Column("<%=columnName %>");
<%
}
}%>
}
}
}
本教程代码参考 EshineASPNet\csswrap\main.cs