c#.net快学系列一之30分钟搞定代码生成

哇咔咔,离上次写文又有几个月了。不过上次写的《这些开源项目,你都知道吗?(持续更新中...)[原创]》受到广大读者的赞赏和推荐,也使得自己更有动力去写技术文章。好了,废话不多说,直接切入正题。

前方高能预警,由于此篇博文适合初学者入门或者各种大牛老男孩怀念那些年我们一起写过的代码生成器,所以请各路时间宝贵的大神慎重查看此篇博文,误入者后果自负!!!

一、前言背景(3分钟)

博主清晰的记得,大三的时候,老师会布置各种课外作业,不过大多是基于数据库增删改查的XX管理系统。此类系统,想必大家伙都懂,自然是无法避免的要编写很多重复性的简单代码。基于XX表的DAL、BLL,其实都不必用三层架构,直接两层多清爽。不过学生时代很多时候都是为了学习而生搬硬套。不像现在各种ORM,写个锤子的DAL。至于大名鼎鼎的T4,用起来似乎智能提示不怎么友好,另外就是针对特性化需求实现起来也麻烦。还有就是各种各样成熟的代码生成器(比如动软),也始终难以满足团队内部的代码生成规则。再加上那时的博主本着一颗造轮子的心,开始脑海中浮现,是否可以做一个工具?主要用以实现对应数据库中表的基础代码的自动生成,包括生成属性、增删改查、实体类等基础代码片断。使开发人员可以节省大量机械式编写代码的时间和重复劳动,而将精力集中于核心业务逻辑的开发。从而使得开发人员能够快速开发项目,缩短开发周期,减少开发成本,大大提高了项目的研发效率,使得开发人员在同样的时间创造出更大的价值。

二、技术储备(2分钟)

1、既然要生成数据库表所对应的代码,那么想必得从数据库获取相关表和字段的基础信息吧?

2、有了相关表和字段的基础信息了,怎么样按照特性化需求和规则生成对应的代码呢?

3、生成的代码如何展现?直接打印到界面还是生成代码文件呢?

三、开始构建(20分钟)

此例子,博主将使用SQL Server 2008 R2 做数据库,使用Winform做工具的UI展示。

1、执行以下sql,即可从SQL server 数据库得到相关表和字段的基础信息(SQL Server 2008 R2 亲测有效)

1 SELECT *
2 FROM master..sysdatabases

获取一个连接上的所有数据库信息

 1 select
 2     [表名]=c.Name,
 3     [表说明]=isnull(f.[value],‘‘),
 4     [列序号]=a.Column_id,
 5     [列名]=a.Name,
 6     [列说明]=isnull(e.[value],‘‘),
 7     [数据库类型]=b.Name,
 8     [类型]= case when b.Name = ‘image‘ then ‘byte[]‘
 9                  when b.Name in(‘image‘,‘uniqueidentifier‘,‘ntext‘,‘varchar‘,‘ntext‘,‘nchar‘,‘nvarchar‘,‘text‘,‘char‘) then ‘string‘
10                  when b.Name in(‘tinyint‘,‘smallint‘,‘int‘,‘bigint‘) then ‘int‘
11                  when b.Name in(‘datetime‘,‘smalldatetime‘) then ‘DateTime‘
12                  when b.Name in(‘float‘,‘decimal‘,‘numeric‘,‘money‘,‘real‘,‘smallmoney‘) then ‘decimal‘
13                  when b.Name =‘bit‘ then ‘bool‘ else b.name end ,
14     [标识]= case when is_identity=1 then ‘是‘ else ‘‘ end,
15     [主键]= case when exists(select 1 from sys.objects x join sys.indexes y on x.Type=N‘PK‘ and x.Name=y.Name
16                         join sysindexkeys z on z.ID=a.Object_id and z.indid=y.index_id and z.Colid=a.Column_id)
17                     then ‘是‘ else ‘‘ end,
18     [字节数]=case when a.[max_length]=-1 and b.Name!=‘xml‘ then ‘max/2G‘
19                   when b.Name=‘xml‘ then ‘2^31-1字节/2G‘
20                   else rtrim(a.[max_length]) end,
21     [长度]=case when ColumnProperty(a.object_id,a.Name,‘Precision‘)=-1 then ‘2^31-1‘
22                 else rtrim(ColumnProperty(a.object_id,a.Name,‘Precision‘)) end,
23     [小数位]=isnull(ColumnProperty(a.object_id,a.Name,‘Scale‘),0),
24     [是否为空]=case when a.is_nullable=1 then ‘是‘ else ‘‘ end,
25     [默认值]=isnull(d.text,‘‘)
26 from
27     sys.columns a
28 left join
29     sys.types b on a.user_type_id=b.user_type_id
30 inner join
31     sys.objects c on a.object_id=c.object_id and c.Type=‘U‘
32 left join
33     syscomments d on a.default_object_id=d.ID
34 left join
35     sys.extended_properties e on e.major_id=c.object_id and e.minor_id=a.Column_id and e.class=1
36 left join
37     sys.extended_properties f on f.major_id=c.object_id and f.minor_id=0 and f.class=1
38
39 获取数据库所有表字段信息

获取一个数据库上的所有表字段信息

2、构建自定义模板,然后替换模板中的标识符

说到自定义模板,无非就是一堆字符串,那这一堆字符串究竟是用XML存储还是TXT文本存储还是其他方式呢?好吧,咱不纠结到底采用哪种存储介质了。基于本文的“30分钟”,博主决定短平快,直接硬编码写死吧!用字符串对象存储起来。

 1 string modelTmp = @"
 2 using System;
 3
 4 namespace #ModelNamespace#
 5 {
 6     /// <summary>
 7     /// #ModelClassDescription#
 8     /// Create By Tool #CreateDateTime#
 9     /// </summary>
10     public class #ModelClassName#
11     {
12 #PropertyInfo#
13     }
14 }";
15
16 实体类模板

实体类模板

1 string modelPropertyTmp = @"
2          /// <summary>
3          /// #PropertyDescription#
4          /// </summary>
5          public  #PropertyType# #PropertyName# { get; set; }";

实体类属性模板

 1 propertyInfo += modelPropertyTmp.Replace(" #PropertyDescription#", propertyDescription)
 2                                                         .Replace(" #PropertyType#", propertyType)
 3                                                         .Replace("#PropertyName#", propertyName);
 4
 5
 6 modelTmp = modelTmp.Replace("#ModelClassDescription#", this.treeView1.SelectedNode.Tag.ToString())
 7                                        .Replace("#CreateDateTime#", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
 8                                        .Replace("#ModelNamespace#", modelNamespace)
 9                                        .Replace("#ModelClassName#", modelClassName)
10                                        .Replace("#PropertyInfo#", propertyInfo);
11
12 标识符替换

替换模板中的标识符

3、采用文本控件将生成的代码打印出来

由于本文旨在让各位读者了解代码生成的原理,故博主花了10多分钟写了一个简单的代码生成器,代码自然有些粗糙,请各位见谅!

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Data;
  4 using System.Data.SqlClient;
  5 using System.Linq;
  6 using System.Windows.Forms;
  7
  8 namespace WindowsTest
  9 {
 10     public partial class CodeCreate : Form
 11     {
 12         private static string S_conStr = "Data Source=127.0.0.1;Initial Catalog=master;Integrated Security=False;user=sa;password=******;";
 13
 14         public CodeCreate()
 15         {
 16             InitializeComponent();
 17         }
 18
 19         public static DataTable ExcuteQuery(string connectionString, string cmdText, List<SqlParameter> pars = null)
 20         {
 21             using (SqlConnection conn = new SqlConnection(connectionString))
 22             {
 23                 using (SqlCommand cmd = new SqlCommand(cmdText, conn))
 24                 {
 25                     if (pars != null && pars.Count > 0) cmd.Parameters.AddRange(pars.ToArray());
 26                     using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
 27                     {
 28                         DataTable dt = new DataTable();
 29                         adp.Fill(dt);
 30                         return dt;
 31                     }
 32                 }
 33             }
 34         }
 35
 36         private void CodeCreate_Load(object sender, EventArgs e)
 37         {
 38             #region 获取所有数据库的信息
 39             string sql = @" SELECT *
 40                             FROM master..sysdatabases
 41                             where dbid>6
 42                             ORDER BY dbid";
 43             #endregion
 44
 45             DataTable dt = ExcuteQuery(S_conStr, sql);
 46             this.treeView1.Nodes.Add("192.168.30.69");
 47             foreach (DataRow dr in dt.Rows)
 48             {
 49                 this.treeView1.Nodes[0].Nodes.Add(dr["name"].ToString());
 50             }
 51
 52             this.treeView1.ExpandAll();
 53         }
 54
 55         private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
 56         {
 57             this.tabControl1.SelectedIndex = 0;
 58
 59             if (e.Node.Level == 0) return;
 60
 61             #region 获取数据库所有表字段信息的sql
 62             string sql = @"
 63 select
 64     [表名]=c.Name,
 65     [表说明]=isnull(f.[value],‘‘),
 66     [列序号]=a.Column_id,
 67     [列名]=a.Name,
 68     [列说明]=isnull(e.[value],‘‘),
 69     [数据库类型]=b.Name,
 70     [类型]= case when b.Name = ‘image‘ then ‘byte[]‘
 71                  when b.Name in(‘image‘,‘uniqueidentifier‘,‘ntext‘,‘varchar‘,‘ntext‘,‘nchar‘,‘nvarchar‘,‘text‘,‘char‘) then ‘string‘
 72                  when b.Name in(‘tinyint‘,‘smallint‘,‘int‘,‘bigint‘) then ‘int‘
 73                  when b.Name in(‘datetime‘,‘smalldatetime‘) then ‘DateTime‘
 74                  when b.Name in(‘float‘,‘decimal‘,‘numeric‘,‘money‘,‘real‘,‘smallmoney‘) then ‘decimal‘
 75                  when b.Name =‘bit‘ then ‘bool‘ else b.name end ,
 76     [标识]= case when is_identity=1 then ‘是‘ else ‘‘ end,
 77     [主键]= case when exists(select 1 from sys.objects x join sys.indexes y on x.Type=N‘PK‘ and x.Name=y.Name
 78                         join sysindexkeys z on z.ID=a.Object_id and z.indid=y.index_id and z.Colid=a.Column_id)
 79                     then ‘是‘ else ‘‘ end,
 80     [字节数]=case when a.[max_length]=-1 and b.Name!=‘xml‘ then ‘max/2G‘
 81                   when b.Name=‘xml‘ then ‘2^31-1字节/2G‘
 82                   else rtrim(a.[max_length]) end,
 83     [长度]=case when ColumnProperty(a.object_id,a.Name,‘Precision‘)=-1 then ‘2^31-1‘
 84                 else rtrim(ColumnProperty(a.object_id,a.Name,‘Precision‘)) end,
 85     [小数位]=isnull(ColumnProperty(a.object_id,a.Name,‘Scale‘),0),
 86     [是否为空]=case when a.is_nullable=1 then ‘是‘ else ‘‘ end,
 87     [默认值]=isnull(d.text,‘‘)
 88 from
 89     sys.columns a
 90 left join
 91     sys.types b on a.user_type_id=b.user_type_id
 92 inner join
 93     sys.objects c on a.object_id=c.object_id and c.Type=‘U‘
 94 left join
 95     syscomments d on a.default_object_id=d.ID
 96 left join
 97     sys.extended_properties e on e.major_id=c.object_id and e.minor_id=a.Column_id and e.class=1
 98 left join
 99     sys.extended_properties f on f.major_id=c.object_id and f.minor_id=0 and f.class=1 ";
100             #endregion
101
102             if (e.Node.Level == 1)
103             {
104                 DataTable dt = ExcuteQuery(S_conStr.Replace("master", e.Node.Text), sql);
105                 this.dataGridView1.DataSource = dt;
106
107                 if (dt.Rows.Count > 0)
108                 {
109                     e.Node.Nodes.Clear();
110                     DataRow[] aryDr = new DataRow[dt.Rows.Count];
111                     dt.Rows.CopyTo(aryDr, 0);
112                     List<string> listTableName = aryDr.Select(a => a["表名"].ToString()).Distinct().ToList();
113                     listTableName.ForEach(a =>
114                     {
115                         e.Node.Nodes.Add(a, a);
116                     });
117                     e.Node.ExpandAll();
118                 }
119             }
120
121             if (e.Node.Level == 2)
122             {
123                 sql += "where [email protected] ";
124                 List<SqlParameter> listSqlParameter = new List<SqlParameter>()
125                 {
126                     new SqlParameter("@TableName",e.Node.Text),
127                 };
128                 DataTable dt = ExcuteQuery(S_conStr.Replace("master", e.Node.Parent.Text), sql, listSqlParameter);
129                 if (dt.Columns.Count > 0)
130                 {
131                     if (dt.Rows.Count > 0)
132                     {
133                         e.Node.Tag = dt.Rows[0]["表说明"].ToString();
134                     }
135                     dt.Columns.Remove("表名");
136                     dt.Columns.Remove("表说明");
137                 }
138                 this.dataGridView1.DataSource = dt;
139             }
140         }
141
142         private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
143         {
144             if (this.tabControl1.SelectedTab.Text == "Model")
145             {
146                 if (this.treeView1.SelectedNode.Level == 2 && this.dataGridView1.Rows.Count > 0)
147                 {
148                     string modelTmp = @"
149 using System;
150
151 namespace #ModelNamespace#
152 {
153     /// <summary>
154     /// #ModelClassDescription#
155     /// Create By Tool #CreateDateTime#
156     /// </summary>
157     public class #ModelClassName#
158     {
159 #PropertyInfo#
160     }
161 }";
162
163                     string modelNamespace = "Model";
164                     string modelClassName = this.treeView1.SelectedNode.Text;
165
166                     string propertyInfo = string.Empty;
167                     foreach (DataGridViewRow dgvr in this.dataGridView1.Rows)
168                     {
169                         string modelPropertyTmp = @"
170         /// <summary>
171         /// #PropertyDescription#
172         /// </summary>
173         public  #PropertyType# #PropertyName# { get; set; }";
174
175                         string propertyDescription = dgvr.Cells["列说明"].Value.ToString().Trim();
176                         string propertyName = dgvr.Cells["列名"].Value.ToString().Trim();
177                         string propertyType = dgvr.Cells["类型"].Value.ToString().Trim();
178
179                         propertyInfo += modelPropertyTmp.Replace(" #PropertyDescription#", propertyDescription)
180                                                         .Replace(" #PropertyType#", propertyType)
181                                                         .Replace("#PropertyName#", propertyName);
182                         propertyInfo += Environment.NewLine;
183                     }
184
185                     modelTmp = modelTmp.Replace("#ModelClassDescription#", this.treeView1.SelectedNode.Tag.ToString())
186                                        .Replace("#CreateDateTime#", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
187                                        .Replace("#ModelNamespace#", modelNamespace)
188                                        .Replace("#ModelClassName#", modelClassName)
189                                        .Replace("#PropertyInfo#", propertyInfo);
190
191                     this.richTextBox1.Text = modelTmp;
192                     Clipboard.SetDataObject(this.richTextBox1.Text);
193                 }
194             }
195         }
196     }
197 }
198
199 主要代码

示例代码

四、结语思考(5分钟)

怎么样,相信各位读者对代码生成有了基本认识了吧!我想普通的代码生成无非就是替换,当然你要是想做一个好一点的代码生成工具,自然是要考虑可扩展性,可维护性,健壮性等。比如可以在左侧的树形菜单那里加上下文菜单,新建连接,断开连接,刷新等扩展功能。在代码打印的区域可以增加另存为,复制等功能。还可以增加相关配置界面,例如命名空间,数据库连接,代码文件默认保存路径等等。自己做的代码生成器可以由自己一直不断的维护,针对特性化需求可以马上实现。好了,本文主要是简洁明了的让各位读者对代码生成原理有一个基本认识,毕竟就30分钟呀!

时间: 2024-10-25 11:09:34

c#.net快学系列一之30分钟搞定代码生成的相关文章

30分钟搞定后台登录界面(103个后台PSD源文件、素材网站)(转)

出处:http://www.cnblogs.com/best/p/6582294.html 目录 一.界面预览 二.PSD源文件预览 三.工具分享 四.资源说明 五.素材下载网站 六.下载 去年八月时要做一个OA系统为了后台界面而烦恼,后来写了一篇博客(<后台管理UI的选择>)介绍了选择过程与常用后台UI,令我想不到的时竟然有许多开发者与我一样都为这个事情而花费不少时间,最后界面效果还是不佳:还好这个OA系统已经基本交付给客户在使用了,但登录界面还是非常难看,这几天花时间修改了一下,感觉还行,

30分钟搞定yii的gridview,你可能只看这一篇就够了 (包含基本配置,下拉筛选,多选删除)

view代码 <?php /* @var $this yii\web\View */ /* @var $form yii\bootstrap\ActiveForm */ /* @var $model \common\models\LoginForm */ use yii\helpers\Url; use yii\helpers\Html; use common\helps\Helps; use common\helps\ArrayHelper; use yii\grid\GridView; us

项目实战:iOS极光推送集成(30分钟搞定)

推送有非常多,如个推.友盟.融云和极光等等.在这里就讲下怎样使用极光推送. 主要内容是将官方文档资料详细汇总并一步一步集成到项目中,您也能够直接去官方文档阅览. 极光推送SDK下载 直接打开官方文档下载最新的SDK 极光网创建APP并上传证书 一.制作推送证书和描写叙述文件:须要注意要制作两个证书,一个是測试证书,一个是公布证书,详细看官方文档截图:点击查看证书制作 直接看<iOS 证书 设置指南>其它的不用看了,废话太多 二.在极光推送官网注冊你的APP吧. bundle id要和你项目一直

30天搞定大数据爬虫项目

详情请交流  QQ  709639943 00.30天搞定大数据爬虫项目 00.零基础实战机器学学习 00.企业级实战 Spark离线和实时电影推荐系统 00.三大项目掌握Storm流计算 00.道路交通实时流量监控预测系统 00.基于Spark2.x新闻网大数据实时分析可视化系统 00.小码哥Java大神班五期 任小龙SSM Spring5 Mybatis SpringMVC 00.Python玩转人工智能框架 TensorFlow 00.web开发级mysql颠覆实战课程 00.微信小游戏入

30天搞定大数据爬虫项目,数据爬虫、全文检索、数据可视化、爬虫项目监控

好,开始今天的文章. 今天主要是来说一下怎么可视化来监控你的爬虫的状态. 相信大家在跑爬虫的过程中,也会好奇自己养的爬虫一分钟可以爬多少页面,多大的数据量,当然查询的方式多种多样.今天我来讲一种可视化的方法. 关于爬虫数据在mongodb里的版本我写了一个可以热更新配置的版本,即添加了新的爬虫配置以后,不用重启程序,即可获取刚刚添加的爬虫的状态数据. 1.成品图 这个是监控服务器网速的最后成果,显示的是下载与上传的网速,单位为M.爬虫的原理都是一样的,只不过将数据存到InfluxDB的方式不一样

白话经典算法系列之六 高速排序 高速搞定

高速排序因为排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被採用,再加上高速排序思想----分治法也确实有用,因此非常多软件公司的笔试面试,包含像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也经常出现高速排序的身影. 总的说来,要直接默写出高速排序还是有一定难度的,因为本人就自己的理解对高速排序作了下白话解释,希望对大家理解有帮助,达到高速排序,高速搞定. 高速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.它採用了一种分治的

懒人办公|30秒搞定PDF文档合并

在日常办公学习中,经常遇到多个PDF文件的情况,一个个点击查看非常麻烦,而且发邮件给客户也不方便,需要添加多个附件,那么问题如何解决呢?其实很简单,仅需将多个PDF合并成一个PDF文档即可,接下来和小编一起学习一下PDF合并技巧吧. 1. PDF365--在线PDF合并 在浏览器直接输入:PDF365.cn,或者百度搜索"PDF365"进入网站: 选择"PDF合并"功能,进入PDF合并页面. 直接拖拽需要合并的PDF文档,或者点击"选择文件"按钮

程序收藏不看系列:一文轻松搞定系统限流

1. 我们为什么需要限流 为了"反脆弱",在微服务复杂拓扑的情况下,限流是保障服务弹性和拓扑健壮的重中之重. 想一想,如果业务推出了一个秒杀活动,而你没有任何的限流措施:当你搭建了一个账号平台,而完全没有对十几个业务方设定流量配额--这些很有可能在特定场合下给你的产品带来大量的业务损失和口碑影响. 我们通常重点关注产品业务层面正向和逆向功能的完成,而对于逆向技术保障,这一点则是企业发展过程中很容易忽视的,所以一旦业务快速增长,这将给你的产品带来很大的隐患. 当然,也不是所有的系统都需要

【前端工程师手册】30分钟搞清楚选择器和权重

有哪些选择器 基本选择器 通配选择器(*) ID选择器(#ID) 类选择器(.className) 元素选择器(tagName) 后代选择器(a b) 子元素选择器(a>b) 相邻后面兄弟元素选择器(a + b) 通用后面兄弟选择器(a ? b) 群组选择器(selector1,selector2,...) 这里面平时不太常用的选择器有相邻后面兄弟选择器和通用后面兄弟选择器首先,很多资料上把它们叫做相邻兄弟选择器和通用兄弟选择器,我觉得这样会有一定的误导意义,例如:` <ul> <