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

上篇文章(深入浅出三层架构)分析了简单三层架构的实现。包括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;点击了一下鼠标…

注解的力量 -----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鼠标请…

响应式布局笔记

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

麦冬

麦冬 中文学名&#xff1a;麦冬 拉丁学名&#xff1a;Ophiopogon japonicus (Linn. f.) Ker-Gawl. 别称&#xff1a;麦门冬、沿阶草 植物界百合科 主要价值&#xff1a; 1、有养阴润肺、益胃生津、清心除烦的功效&#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)完成独立功…

CentOS6.4 Install FTP

目录 安装参考传输模式遇到无法显示远程文件夹报错安装参考 https://www.cnblogs.com/walblog/articles/7890226.html 传输模式 主动模式被动模式遇到无法显示远程文件夹报错 点击属性设置&#xff1a; 搞定。 转载于:https://www.cnblogs.com/mysticbinary/articles/11271647.…

用于单元测试的JUnit教程–最终指南(PDF下载)

编者注&#xff1a; 我们在Java Code Geeks上提供了许多JUnit教程&#xff0c;例如JUnit入门示例 &#xff0c; 使用断言和注释的 JUnit 示例 &#xff0c; JUnit注释示例等。 但是&#xff0c;为了方便读者&#xff0c;我们希望将所有JUnit功能收集在一份详细的指南中。 我们…

EF 拉姆达 linq if else (整理)

首先想到&#xff1a;结果不正确&#xff01; var data0 db.T_Plants2; //这里加.AsQueryable()if (locationType 1){.Where(d > d.NaturalEcosystem true);}else{.Where(d > d.BuiltUpArea true);}.Select(d > new{AnimalID d.PlantID,Species d.Species,}).To…

用jOOQ用Java编写SQL

jOOQ是“数据库优先”的类型安全的SQL API&#xff0c;使您可以直观地用Java编写SQL&#xff0c;就像Java编译器本身支持SQL语言一样。 所有数据库模式&#xff0c;表&#xff0c;列&#xff0c;过程和其他对象均作为Java对象提供&#xff0c;可以直接在jOOQ SQL API中使用。 …

BizTalk开发系列(十二) Schema设计之Group与Order

更多内容请查看&#xff1a;BizTalk动手实验系列目录 BizTalk 开发系列 开发BizTalk项目的时候会先约定各系统之间往来的消息格式. 由于BizTalk内部唯一使用XML文档。因此消息的格式为XML Schema(XML Schema 用于描述 XML 文档的结构)。虽然BizTalk提供了对于XML消息的验证功能…

题解:CF1914E-Game with Marbles

题解&#xff1a;CF1914E-Game with Marbles 事先说明一下&#xff0c;本题解不讲解简单数据范围的算法&#xff0c;因为复杂数据范围的就很简单。 这道题的大体意思是这样的&#xff1a;小A有颜色为i(i1~n)的小球a[i]个&#xff0c;小B有颜色为i(i1~n)的小球b[i]个。现在他们…

【canvas系列】canvas实现“ 简单的Amaziograph效果”--画对称图【强迫症福利】

标题很难引人入胜&#xff0c;先放个效果图好了 如果图片吸引不了你&#xff0c;那我觉得也就没啥看的了。 demo链接&#xff1a; https://win7killer.github.io/demo_set/html_demo/canvas/can_demo/draw_roll_2.html ************************************************* 上…

python3基础:字符串、文本文件

字符串&#xff1a; 练习1&#xff1a; str "大胖三百磅不是二百磅陪着一百磅的小胖" print(str.replace("磅", "斤")) # 替换所有 print(str.replace("磅", "斤", 2)) # 替换两次len len(str) # 这句话的字数长度 pri…

[Python][小知识][NO.3] Python 使用系统默认浏览器打开指定URL的网址

1、前言 一般用到的地方&#xff1a; GUI交互界面下&#xff0c;单击某个按钮实现打开指定网址。 某帮助菜单项目&#xff0c;需要跳转网页显示时。 O.O 某XX程序&#xff0c;需要植入网页弹窗广告时... 2、方法 调用 webbrowser 包中的 open 函数即可。 (没安装该包的 CMD命令…

MyEclipse 10优化技巧

MyEclipse 10优化速度方案仍然主要有这么几个方面&#xff1a;去除无需加载的模块、取消冗余的配置、去除不必要的检查、关闭更新。第一步: 去除不需要加载的模块一个系统20%的功能往往能够满足80%的需求&#xff0c;MyEclipse也不例外&#xff0c;我们在大多数时候只需要20%的…

HTML知识点总结之img、scirpt、link标签

<img>元素 使用<img>可以在网页插入一个图片&#xff0c;但实际上<img>标签并不会在网页中直接插入图像&#xff0c;而是从网页上链接图像。 <img>的主要属性 &#xff08;1&#xff09;src属性&#xff1a;图片的路径。 &#xff08;2&#xff09;alt…

laravel中的自定义函数的加载和第三方扩展库加载

一.自定义公共函数 1. 创建文件 app/Helpers/functions.php 2. 修改项目 composer.json 3.运行composer dump-auto 4.OK&#xff0c;然后你就可以在任何地方用到 app/Helpers/functions.php 中的函数了。 二.添加第三方扩展库 1.确定你要放第三方库的目录&#xff0c;比如还是刚…