简单代码生成器原理剖析(一)

上篇文章(深入浅出三层架构)分析了简单三层架构的实现。包括Model,DAL(数据访问层),BLL(业务逻辑层)的实现。

实际开发中,由于重复代码的操作,会花费大量时间,如果以代码生成器来自动生成三层架构代码,即节省精力,又可以节省大量的时间来做其他业务逻辑的代码,提高开发效率。

常用的代码生成器有:动软,CodeSmith 等。

简单代码生成器的基本功能描述:

一键生成Model,DAL,BLL,包括对应数据库中表的Model的自动生成,包括生成属性、添加、修改、删除、查询。

界面展示:

生成器开发技术要点:

  1. 查询系统视图:INFORMATION_SCHEMA.TABLES、 INFORMATION_SCHEMA.COLUMNS  可以获得数据库中表、列的相关信息。
  2. 字符串的拼接:StringBuilder的使用,其AppendLine()会自动换行。
  3. 将字符串写入文本文件:File.WriteAllText()
  4. 为了降低开发难度,先假设条件多一些,如表的主键都为Id,且自动增长,之后再逐步完善

关键代码:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;

namespace CodeGenerator
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 执行ExecuteDataTable(),得到DataTable
/// </summary>
/// <param name="cmdText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public DataTable ExecuteDataTable(string cmdText,
params SqlParameter[] parameters)
{
using (SqlConnection conn=new SqlConnection(txtConnStr.Text))
{
conn.Open();
using(SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = cmdText;
cmd.Parameters.AddRange(parameters);
using (SqlDataAdapter adapter=new SqlDataAdapter (cmd))
{
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}

}

private void Form1_Load(object sender, EventArgs e)
{
txtConnStr.Text = @"Data Source=EYES\SQLEXPRESS;Initial Catalog=SanCeng;Integrated Security=True";
}

private void btnConnStr_Click(object sender, EventArgs e)
{

//清空
clbTables.Items.Clear();
//查询系统试图
string sql = "select * from INFORMATION_SCHEMA.TABLES";
DataTable dt = ExecuteDataTable(sql);
//根据系统视图取得TABLE_NAME
foreach (DataRow row in dt.Rows)
{
string tablename = Convert.ToString(row["TABLE_NAME"]);
clbTables.Items.Add(tablename);
}

}

private void btnGo_Click(object sender, EventArgs e)
{
//连接字符串
//方法AppendLine()追加字符串且自动执行换行

foreach (string tableName in clbTables.CheckedItems)
{
string sql = "select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@TABLE_NAME ";
DataTable dt = ExecuteDataTable(sql,new SqlParameter("TABLE_NAME",tableName));

#region 生成Model
CreatModel(tableName, dt);
#endregion

#region 生成DAL


CreatDAL(tableName, dt);
#endregion
#region 生成BLL
CreatBLL(tableName, dt);
#endregion
}
}

private static void CreatDAL(string tableName, DataTable dt)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine("using System.Linq;");
sb.AppendLine("using System.Text;");
sb.AppendLine("using 三层架构Demo.Model;");
sb.AppendLine("using System.Data.SqlClient;");
sb.AppendLine("using System.Data;");
sb.AppendLine("namespace 三层架构Demo.DAL");
sb.AppendLine("{");
sb.AppendLine("class " + tableName + "DAL");
sb.AppendLine("{");
//去掉Id
sb.AppendLine(" public int Addnew(" + tableName + " model)");
sb.AppendLine("{");
List<String> cols = new List<string>();
List<String> parameters = new List<string>();
foreach (DataRow row in dt.Rows)
{
string col = Convert.ToString(row["COLUMN_NAME"]);
string parameter = "";
if (col.ToLower()!="id")
{
parameter= "@" + Convert.ToString(row["COLUMN_NAME"]);
cols.Add(col);
parameters.Add(parameter);
}
//parameters.Add(parameter)放外面加上一个NULL,所以会多出一个逗号
// parameters.Add(parameter);

}

sb.AppendLine("string sql = \"insert into " + tableName + "(" + String.Join(",", cols) + ") output inserted.Id values(" + String.Join(",", parameters) + ")\";");
sb.AppendLine("object obj= SQLHelper.ExecuteScalar(sql");

foreach (DataRow row in dt.Rows)
{
string col = Convert.ToString(row["COLUMN_NAME"]);
if (col.ToLower() != "id")
{
sb.AppendLine(",new SqlParameter(\"" + col + "\",model." + col + ")");
}

}
sb.AppendLine(");");
sb.AppendLine("return Convert.ToInt32(obj);");
sb.AppendLine("}");
//Delete方法

sb.AppendLine(" public int Delete(int id)");
sb.AppendLine("{");
sb.AppendLine(" string sql = \"delete from " + tableName + " where Id=@Id\";");
sb.AppendLine("return SQLHelper.ExecuteNonQuery(sql,new SqlParameter(\"Id\",id));");
sb.AppendLine("}");

//Update方法
sb.AppendLine("public int Update("+tableName+" model)");
sb.AppendLine("{");
string[] uParams1=(from col in cols select col+"=@"+col).ToArray();

sb.AppendLine(" string sql = \"update "+tableName+" set "+String.Join(",",uParams1)+" where Id=@Id\";");

string[] uParams2 = (from col in cols select "new SqlParameter(\"" + col + "\",model." + col + ")").ToArray();
sb.AppendLine(" return SQLHelper.ExecuteNonQuery(sql, " + String.Join(",", uParams2) + " ,new SqlParameter(\"Id\",model.Id));");
sb.AppendLine("}");

//GetId方法
sb.AppendLine(" public "+tableName+" Get(int id)");
sb.AppendLine("{");
sb.AppendLine("string sql=\"select * from "+tableName+" where Id=@Id\";");
sb.AppendLine(" DataTable dt=SQLHelper.ExecuteDataTable(sql,new SqlParameter(\"Id\",id));");
sb.AppendLine("if (dt.Rows.Count<=0)");
sb.AppendLine("{");
sb.AppendLine(" return null;");
sb.AppendLine("}");
sb.AppendLine(" else if (dt.Rows.Count==1)");
sb.AppendLine("{");
sb.AppendLine(""+tableName+" model1 = new "+tableName+"();");
foreach (DataRow row in dt.Rows)
{
string col = Convert.ToString(row["COLUMN_NAME"]);
string dataType = Convert.ToString(row["data_TYPe"]);
sb.AppendLine("model1." + col + " = Convert." + Get(GetType(dataType).ToString()) + "(dt.Rows[0][\"" + col + "\"]);");

}
sb.AppendLine("return model1;");
sb.AppendLine("}");
sb.AppendLine("else");
sb.AppendLine("{");
sb.AppendLine(" throw new Exception(\"数据库中有两条及以上重复数据\");");
sb.AppendLine("}");
sb.AppendLine("}");

//IEnumerable()方法
sb.AppendLine(" public IEnumerable<"+tableName+"> GetAll()");
sb.AppendLine("{");
sb.AppendLine(" string sql = \"select * from "+tableName+"\";");
sb.AppendLine("DataTable dt = SQLHelper.ExecuteDataTable(sql);");
sb.AppendLine(" List<"+tableName+"> list = new List<"+tableName+">();");
sb.AppendLine(" foreach (DataRow row in dt.Rows)");
sb.AppendLine("{");
sb.AppendLine("" + tableName + " model = new " + tableName + "();");
foreach (DataRow row in dt.Rows)
{
string col = Convert.ToString(row["COLUMN_NAME"]);
string dataType = Convert.ToString(row["data_TYPE"]);
sb.AppendLine("model." + col + " = Convert." + Get(GetType(dataType).ToString()) + "(row[\"" + col + "\"]);");

}
sb.AppendLine(" list.Add(model);");
sb.AppendLine("}");
sb.AppendLine("return list;");
sb.AppendLine("}");
sb.AppendLine("}");
sb.AppendLine("}");
File.WriteAllText(@"d:\"+tableName+"DAL.cs",sb.ToString());


}
/// <summary>
/// 数据库类型转换为C#类型
/// </summary>
/// <param name="dataType"></param>
/// <returns></returns>
private static Type GetType(string dataType)
{
switch (dataType.ToLower())
{
case "nvarchar":
case "varchar":
case "nchar":
case "char":
return typeof(string);
case "int" :
return typeof(int);
case "bigint":
return typeof(long);
case "bit":
return typeof(bool);
case "datetime":
return typeof(DateTime);
default:
return typeof(object);
}

}

private static string Get(string dataType)
{

switch (dataType.ToLower())
{
case "system.string":
return "ToString";
case "system.int32":
return "ToInt32";
case "system.int64":
return "ToInt64";
case "system.datetime":
return "ToDateTime";
case "system.boolean":
return "ToBoolean";

default:
throw new Exception("找不到匹配的数据类型");

}
}
private static void CreatModel(string tableName, DataTable dt)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine("using System.Linq;");
sb.AppendLine("using System.Text;");
sb.AppendLine("namespace 三层架构Demo.Model");
sb.AppendLine("{");
sb.AppendLine("");
sb.AppendLine("class " + tableName);
sb.AppendLine("{");

foreach (DataRow row in dt.Rows)
{
string dataType = Convert.ToString(row["DATA_TYPE"]);

string columnName = Convert.ToString(row["COLUMN_NAME"]);

sb.AppendLine("public " + GetType(dataType) + " " + columnName + " { get;set;}");
}
sb.AppendLine("}");
sb.AppendLine("}");
File.WriteAllText(@"d:\" + tableName + ".cs", sb.ToString());
//MessageBox.Show(sb.ToString());

}

private static void CreatBLL(string tableName, DataTable dt)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine("using System.Linq;");
sb.AppendLine("using System.Text;");
sb.AppendLine("using 三层架构Demo.Model;");
sb.AppendLine("using 三层架构Demo.DAL;");
sb.AppendLine("using System.Data.SqlClient;");
sb.AppendLine("using System.Data;");
sb.AppendLine("namespace 三层架构Demo.BLL");
sb.AppendLine("{");
sb.AppendLine("class " + tableName+"BLL");
sb.AppendLine("{");
sb.AppendLine("public int Addnew("+tableName+" model)");
sb.AppendLine("{");
sb.AppendLine(" return new "+tableName+"DAL().Addnew(model);");
sb.AppendLine("}");
sb.AppendLine(" public int Delete(int id)");
sb.AppendLine("{");
sb.AppendLine(" return new "+tableName+"DAL().Delete(id);");
sb.AppendLine("}");
sb.AppendLine(" public int Update("+tableName+" model)");
sb.AppendLine("{");
sb.AppendLine(" return new " + tableName + "DAL().Update(model);");
sb.AppendLine("}");
sb.AppendLine(" public "+tableName+" Get(int id)");
sb.AppendLine("{");
sb.AppendLine(" return new "+tableName+"DAL().Get(id);");
sb.AppendLine("}");
sb.AppendLine(" public IEnumerable<"+tableName+"> GetAll()");
sb.AppendLine("{");
sb.AppendLine(" return new "+tableName+"DAL().GetAll();");
sb.AppendLine("}");
sb.AppendLine("}");
sb.AppendLine("}");
File.WriteAllText(@"d:\" + tableName + "BLL.cs", sb.ToString());
}
}
}



总结:
忽略了很多限制因素,所以代码生成器功能不是很完善。随着要考虑的条件增多,代码生成器越加复杂。但万变不离其中,只要有耐心,继续AppendLine()添加新语句,相信功能会愈加完善。“
工欲善其事必先利其器“,程序员不仅会用代码生成器,而且知道其原理才是优秀的程序员。切勿”知其然而不知其所以然“。


 

 

 

 

 

 

转载于:https://www.cnblogs.com/OceanEyes/archive/2012/02/16/CodeGenerator.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361664.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt学习之路(4):初探信号槽

看过了简单的Hello, world! 之后&#xff0c;下面来看看Qt最引以为豪的信号槽机制&#xff01;所谓信号槽&#xff0c;简单来说&#xff0c;就像是插销一样&#xff1a;一个插头和一个插座。怎么说呢&#xff1f;当某种事件发生之后&#xff0c;比如&#xff0c;点击了一下鼠标…

当字符串为空但不为空时

介绍 我团队中的一名初级程序员遇到了一个有趣的错误。 我已经不止一次看到它的症状。 这篇文章是寻找什么以及将来如何防止它。 我还将探讨该问题的不同解决方案。 病征 有问题的代码看起来做得不错。&#xff1a; if(trouble ! null && !trouble.isEmpty()) { Syst…

注解的力量 -----Spring 2.5 JPA hibernate 使用方法的点滴整理(六): 一些常用的数据库 注解...

一、 实体 Bean 每个持久化POJO类都是一个实体Bean, 通过在类的定义中使用 Entity 注解来进行声明。 声明实体Bean Entitypublic class Flight implements Serializable { Long id; Id public Long getId() { return id; } public void setId(Long id) { this.id id; }} E…

SWT鼠标单击实现

最近&#xff0c;我做了一些SWT定制小部件的开发&#xff0c;偶然发现了一个问题&#xff0c; 为什么没有默认的SWT鼠标单击侦听器&#xff1f; 由于这个主题有时会提出&#xff0c;所以我认为写一两句话来说明背后的理性基础以及如何实现鼠标单击通常不会受到伤害。 SWT鼠标请…

第三周进度总结

本周大部分时间花费在了考驾照上&#xff0c;所以没有在学习上用太多的时间。在不多的时间里看完了老师推荐的《大道至简》这本书&#xff0c;从书中学到了很多编程方面的思想&#xff0c;受益匪浅。还完成了2个代码的编译&#xff0c;一个是判断AB和C的关系&#xff0c;这个并…

页面中插入视频的方法---video/embed/iframe总结

1. video标签 当前主流的方法当然是HTML5中的video标签了&#xff0c;但是 当前&#xff0c;video 元素只支持三种视频格式&#xff1a; Ogg 带有 Theora 视频编码和 Vorbis 音频编码的 Ogg 文件 MPEG4 带有 H.264 视频编码和 AAC 音频编码的 MPEG 4 文件 WebM 带有 VP…

Spring请求级备忘录

介绍 记忆化是一种方法级别的缓存技术&#xff0c;用于加快连续调用的速度。 这篇文章将演示如何仅使用Spring AOP实现任何数据源的请求级可重复读取。 Spring缓存 Spring提供了非常有用的缓存抽象 &#xff0c;允许您将应用程序逻辑与缓存实现细节分离。 Spring Caching使用…

从一个帖子看 所谓“知乎” 的真实水平

帖子地址&#xff1a;https://www.zhihu.com/question/27535713 明末尤其是崇祯后期&#xff0c;最大的背景是天灾瘟疫反复肆虐&#xff0c;三成人死于饥荒&#xff0c;三成人死于瘟疫&#xff0c;四成为生存从贼是当时中原的真实写照。 抛开这个最大前提不谈&#xff0c;去乱弹…

新的开始,新的挑战

我承认&#xff0c;我还比较年轻&#xff0c;我承认&#xff0c;我的经验很少&#xff0c;我承认&#xff0c;我的能力还是比较小。。。。。。 但是&#xff0c;我不怕&#xff0c;我敢往前走&#xff0c;错了我就改&#xff0c;不行我就努力&#xff0c; 要么痛苦的坚持到游戏…

响应式布局笔记

一. 布局设计 固定布局&#xff1a;以像素作为页面的基本单位&#xff0c;不管设备屏幕及浏览器宽度&#xff0c;只设计一套尺寸&#xff1b; 可切换的固定布局&#xff1a;同样以像素作为页面单位&#xff0c;参考主流设备尺寸&#xff0c;设计几套不同宽度的布局。通过设别的…

麦冬

麦冬 中文学名&#xff1a;麦冬 拉丁学名&#xff1a;Ophiopogon japonicus (Linn. f.) Ker-Gawl. 别称&#xff1a;麦门冬、沿阶草 植物界百合科 主要价值&#xff1a; 1、有养阴润肺、益胃生津、清心除烦的功效&#xff0c;用于肺燥干咳、阴虚痨嗽、喉痹咽痛、津伤口渴、…

如何使用Callable和FutureTask

介绍 从Java 1.5开始&#xff0c;在java.util.concurrent下有了新的对象集。 该程序包具有许多不同的类&#xff0c;包括线程队列。 当我用Java 1.2编程时&#xff0c;我本可以使用那些&#xff01; 当我开始看这些新玩具时&#xff0c;我变得犹豫不决。 这是什么可调用的东西&…

NodeJS的安装与使用

Node.js 就是运行在服务端的 JavaScript。越来越多的人在使用它&#xff0c;通过他我们可以用JavaScript来构建后台。对于前端程序员而言&#xff0c;不言而喻这是一条多么令人振奋的消息。对于后台程序员而言&#xff0c;这也是一种很不错的选择。 下面我就来讲解下nodejs的安…

转载 300年前的黑色“巫女”

1741年&#xff0c;北极。 白令招呼水手们把船靠上小岛的时候&#xff0c;一排黑色的鸬鹚站在陡峭的悬崖上&#xff0c;像一群黑色的巫女&#xff0c;一动不动朝着他们张望。白令顿时有了一种不祥的预兆。 果然&#xff0c;刚刚上岛&#xff0c;就遭到古怪的兰狐的袭击&#xf…

华为在爱尔兰增设150个LTE研发职位

据国外媒体报道中国电信和网络跨国公司华为技术预计将在未来两年内在爱尔兰增设150个职位。华为公司目前设在爱尔兰都柏林、阿斯隆和科克的业务处共有50名员工。现在&#xff0c;公司已经投标竞购牌照&#xff0c;目的是为在爱尔兰推出第四代宽带进行基础设施开发。华为公司爱尔…

Java EE 7 / JAX-RS 2.0 – REST上的CORS

Java EE REST应用程序通常在开箱即用的开发机器上运行良好&#xff0c;该开发机器上所有服务器端资源和客户端UI均指向“ localhost”或127.0.0.1。 但是&#xff0c;当涉及跨域部署时&#xff08;当REST客户端不再与托管REST API的服务器位于同一域时&#xff09;&#xff0c;…

jQuery框架-1.jQuery基础知识

jQuery简介 jQuery&#xff0c;顾名思义是JavaScript和查询&#xff08;Query&#xff09;&#xff0c;jQuery是免费、开源的。它可以简化查询DOM对象、处理事件、制作动画、处理Ajax交互过程且兼容多浏览器的javascript库&#xff0c;核心理念是write less,do more(写得更少,…

用CornerStone配置SVN,HTTP及svn简单使用说明

原文地址&#xff1a;&#xff1a;&#xff1a;http://my.oschina.net/joanfen/blog/194491#OSC_h2_3 一、下载地址二、安装破解方法三、添加repository 1.SVN配置 2.HTTP配置四、使用简介 1.上传项目到repository 2.下载项目 3.版本管理 a)先更新后提交 b)完成独立功…

联系随笔2---在tomcat服务器上发布servlet应用程序

问题二&#xff1a;在tomcat服务器上发布servlet应用程序 1,new->Dynamic Web Project写工程名字->next->next在Generate web.xml文件上打勾勾->finish. 2&#xff0c;在工程名字上&#xff0c;new->servlet。在create Servlet对话框中填写java package包名字和…

Apache Lucene 5.0.0即将发布!

终于&#xff0c;在一系列强大的4.x功能&#xff08;最近是4.10.2&#xff09;发布之后&#xff0c;我们终于在努力开发另一个主要的Apache Lucene版本&#xff01; 没有确切时间的承诺&#xff08;完成时就完成了&#xff01;&#xff09;&#xff0c;但是我们已经有一个自愿…