代码生成器原理及示例

在三层架构中Model、DAL、BLL层有必要分开,其中有些代码可以由代码生成器生成。虽然网络已经有成熟的代码生成器,但是掌握代码生成器的编写方法、原理还是很有必要的。下面通过一个例子简要介绍代码生成器编写过程,并给出一个具备基本功能的范例雏形。以抛砖引玉。

大家好,又见面了,我是你们的朋友全栈君。

      在三层架构中Model、DAL(Data Access Layer)、BLL层有必要分开,其中有些代码可以由代码生成器生成。虽然网络已经有成熟的代码生成器,但是第三方代码生成器在实际应用场景中,生成的代码经常还需要在其基础上修改。修改其代码就不如修改代码生成器本身。所以掌握代码生成器的编写方法、原理还是很有必要的。

      下面通过一个例子简要介绍代码生成器编写过程,并给出一个具备基本功能的范例雏形。以抛砖引玉。

      

成果展示截图:

 代码生成器原理及示例

图 代码生成器界面截图

代码生成器原理及示例

DAL结果截图

代码生成器原理及示例

Model截图

后台代码展示如下:

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.Configuration;
using System.Data.SqlClient;
namespace 我的代码生成器
{
public partial class FormCodeGenerater : Form
{
public FormCodeGenerater()
{
InitializeComponent();
}
/// <summary>
/// 使用ConfigurationManager读取App.config中的字符串。
/// </summary>
static string connStr = ConfigurationManager.ConnectionStrings["dbConnStr"].ConnectionString;
#region 方法
/// <summary>
/// 获取数据库中所有的字段名称
/// </summary>
private List<string> GetFields(string _connectString, string _tableName)
{
List<string> tableNameList = new List<string>();
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from " + _tableName;
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds);
DataTable table = ds.Tables[0];
foreach (DataColumn col in table.Columns)
{
string tmpString = col.ColumnName + "," + col.AllowDBNull + "," + col.DataType;
tableNameList.Add(tmpString);
}
}
}
return tableNameList;
}
/// <summary>
/// 获取数据库表名
/// </summary>
/// <param name="_connectString"></param>
/// <returns></returns>
private List<string> GetTableNames(string _connectString)
{
List<string> resultList = new List<string>();
string databaseName = GetDataBaseNameFromConnectString(_connectString);//todo 取出数据库名称
//string.take
string sql = "SELECT Name FROM " + databaseName + "..SysObjects Where XType='U' ORDER BY Name";
DataTable dt = ExecuteDataTable(_connectString, sql);
//todo装载resultList
foreach (DataRow row in dt.Rows)
{
string tmpString = row[0].ToString();
resultList.Add(tmpString);
}
return resultList;
}
/// <summary>
/// 从连接字符串读取出数据库名称
/// </summary>
/// <returns></returns>
private string GetDataBaseNameFromConnectString(string _connectString)
{
try
{
string[] strArray = _connectString.Split(';');
string resultStr = strArray[1].Substring(16);
return resultStr;
}
catch { return string.Empty; }
}
/// <summary>
/// 执行sql语句,返回datatable
/// </summary>
/// <param name="_connectString"></param>
/// <param name="sql"></param>
/// <returns></returns>
private DataTable ExecuteDataTable(string _connectString, string sql)
{
using (SqlConnection conn = new SqlConnection(_connectString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds);
DataTable table = ds.Tables[0];
return table;
}
}
}
/// <summary>
///  如果列允许为null,并且列在c#中的类型是不可空的(值类型)
/// </summary>
/// <param name="_column"></param>
/// <returns></returns>
private static string GetDataTypeName(DataColumn _column)
{
//如果列允许为null,并且列在c#中的类型是不可空的(值类型)
if (_column.AllowDBNull && _column.DataType.IsValueType)
{
return _column.DataType + "?";
}
else
{
return _column.DataType.ToString();
}
}
#endregion
#region 事件
private void FormCodeGenerater_Load(object sender, EventArgs e)
{
textBoxConnStr.Text = connStr;
}
private void buttonConnect_Click(object sender, EventArgs e)
{
try
{
//绑定Combobox
comboBoxTables.Items.Clear();
List<string> TableNameList = GetTableNames(connStr);
comboBoxTables.Items.AddRange(TableNameList.ToArray());
if (comboBoxTables.Items.Count > 0)
comboBoxTables.SelectedIndex = 0;
buttonGenerateCode.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void buttonGenerateCode_Click(object sender, EventArgs e)
{
string tableName = (string)comboBoxTables.SelectedItem;
if (tableName == null)
{
MessageBox.Show("请选择要生成的表");
return;
}
//大量字符串拼接,需要使用StringBuilder效率更高
//Append()拼接
//AppendLine()后面加一行
CreateModelCode(connStr,tableName);
CreateDALCode(connStr, tableName);
}
private void CreateModelCode(string _connStr,string _tableName)
{
DataTable table = ExecuteDataTable(_connStr, "select top 0 * from " + _tableName);
StringBuilder sb = new StringBuilder();
sb.Append("public class ").Append(_tableName).AppendLine("{");
foreach (DataColumn col in table.Columns)
{
sb.Append("     public ").Append(GetDataTypeName(col)).Append(" ")
.Append(col.ColumnName).AppendLine("{get;set;}");             
}
sb.AppendLine("}");
richTextBoxModelCode.Text = sb.ToString();
}
/// <summary>
/// 创建DAL代码
/// </summary>
/// <param name="_tableName"></param>
private void CreateDALCode(string _connStr, string _tableName)
{
string blanksString = "   ";
DataTable table = ExecuteDataTable(_connStr, "select top 0 * from " + _tableName);
StringBuilder sb = new StringBuilder();
sb.Append("public class ").Append(_tableName).AppendLine("DAL").AppendLine("{");
//ToModel开始
sb.Append("   private ").Append(_tableName).AppendLine(" ToModel(DataRow row)").Append(blanksString + "{");
sb.Append(blanksString + _tableName).AppendLine(" model=new " + _tableName + "();");
foreach (DataColumn col in table.Columns)
{
//无论列是否为空,都进行判断DbNull的处理
//model.Id=(Guid)SqlHelper.FromDbValue(row["Id"]);
// \表示转义字符
sb.Append(blanksString+"model.").Append(col.ColumnName).Append("=(").Append(GetDataTypeName(col)).Append(")SqlHelper.FromDbValue(row[\"").Append(col.ColumnName).AppendLine("\"]);");
}
sb.Append("return model;").AppendLine("}");
//ToModel的结束
//ListAll开始
//public IEnumerable<Department> ListAll()
sb.Append("public IEnumerable<").Append(_tableName).AppendLine("> ListAll()");
sb.AppendLine("{");
sb.Append(blanksString+"List<").Append(_tableName).Append("> list=new List<").Append(_tableName).AppendLine(">();");
sb.Append(blanksString+"DataTable dt=SqlHelper.ExecuteDataTable(\"").Append("select * from "+_tableName).AppendLine("\");");
sb.AppendLine("foreach(DataRow row in dt.Rows)");
sb.Append("{");
sb.Append(_tableName).Append(" model=ToModel(row);");
sb.AppendLine("list.Add(model);}");
sb.AppendLine("return list;");
sb.AppendLine("}");
//ListAll结束
sb.AppendLine(blanksString + "public static object FromDbValue(object value)");
sb.AppendLine(blanksString+"{");
sb.Append(blanksString+"  if (value == DBNull.Value)");
sb.AppendLine(blanksString+"  {return null;}");
sb.Append("else");
sb.AppendLine(blanksString + "  {return value;}");
sb.AppendLine(blanksString+"}");
//FromDbValue()结束
sb.AppendLine("}");
richTextBoxDALCode.Text = sb.ToString();
}
/// <summary>
/// 以数组形式返回列名。
/// </summary>
/// <param name="_table"></param>
/// <returns></returns>
private static string[] GetParamColumnNames(DataTable _table)
{
string[] colNames = new string[_table.Columns.Count];
for (int i = 0; i < colNames.Count(); i++)
{
DataColumn dataCol=_table.Columns[i];
colNames[i] ="@"+ dataCol.ColumnName;
}
return colNames;
}
/// <summary>
/// 以数组形式返回列名。
/// </summary>
/// <param name="_table"></param>
/// <returns></returns>
private static string[] GetColumnNames(DataTable _table)
{
string[] colNames = new string[_table.Columns.Count];
for (int i = 0; i < colNames.Count(); i++)
{
DataColumn dataCol = _table.Columns[i];
colNames[i] =  dataCol.ColumnName;
}
return colNames;
}
#endregion
}
}

将连接字符串存储到App.Config中

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="dbConnStr" connectionString="Data Source=xxx.xxx.xx.xx,xxxx;Initial Catalog=LightningScienceAndTechnology;User ID=xx;Password=xxxxxxxxxx"/>
</connectionStrings>
</configuration>

SqlHelper相关代码

 public class SqlHelper
{
static  string connStr = ConfigurationManager.ConnectionStrings["dbConnStr"].ConnectionString;
public static object ExecuteScalar(string sql, params SqlParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteScalar();
}
}
}
public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteNonQuery();
}
}
}
public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd =conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddRange(parameters);
SqlDataAdapter sqlAdapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sqlAdapter.Fill(ds);
return ds.Tables[0];
}
}
}
public static object FromDbValue(object value)
{
if (value == DBNull.Value)
{
return null;
}
else
{
return value;
}
}
public static object ToDbValue(object value)
{
if (value == null)
{
return DBNull.Value;
}
else
{
return value;
}
}
}

注意事项:

1 StringBuilder字符串拼接,在大量字符串拼接的情况下,效率比”+”要高。

2 在Model中考虑到可空类型(比如:int?)

3 app.Config的读取需要引用System.Configuration


做技术:

懂了原理:掌握10%

实现功能:
掌握90%
优雅地实现:
掌握100%。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/127021.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • pycharm基础设置_pycharm环境变量配置

    pycharm基础设置_pycharm环境变量配置一、更改字体大小Ctrl+Alt+S打开设置界面二、设置背景颜色Ctrl+Alt+S打开设置界面

  • 用matlab产生时域离散信号实验报告(有关数字信号处理)

    1.正弦序列离散正弦序列的MATLAB表示与连续信号类似,只不过是用stem函数而不是用plot函数来画出序列的波形。下面就是正弦序列的MATLAB源程序。%正弦序列实现程序k=0:39;fk=sin(pi/6*k);stem(k,fk)2.指数序列离散指数序列的一般形式为,可用MATLAB中的数组幂运算(即点幂运算)c*来实现。下面为用MATLAB编写绘制离散时

  • 数据库mdf和ldf文件怎么打开_mdf数据库文件用什么打开

    数据库mdf和ldf文件怎么打开_mdf数据库文件用什么打开AdventureWorks2008数据文件下载(含mdf和ldf文件) 下载地址:http://pan.baidu.com/s/1kTA0EbH   (26MB左右。解压之后有196MB左右,直接附加即可使用。)

  • 前端缓存方案「建议收藏」

    前端缓存方案「建议收藏」前端几种本地缓存机制_蜗牛小前的博客-CSDN博客_前端本地缓存在漫长的前端开发过程中,我们常用的几种本地缓存机制:Cookie,LocalStorge,SessionStorge1.Cookie的特点1)cookie的大小受限制,cookie大小被限制在4KB,不能接受像大文件或邮件那样的大数据。2)只要有请求涉及cookie,cookie就要在服务器和浏览器之间来回传送(这解释为什么本地文件不能测试cookie)。而且coo…https://blog.csdn.net/weixin_397170..

    2022年10月28日
  • windows10添加开机启动项怎么设置_注册表添加开机启动项

    windows10添加开机启动项怎么设置_注册表添加开机启动项在日常生活中,偶尔要求其中的软件在开机时便能自动启动,比如MySQL一般被设置为自启动项。今天将为大家介绍window10中如何添加开机启动项。操作过程:1、按下win+R调出运行窗口,并输入“shell:startup”即可进入开机启动文件夹。2、开机启动文件夹如图所示,此时文件夹中内容为空。3、如果想要添加启动项,可以将软件快捷方式移入开机启动文件夹中,比如移入“福昕阅读器”。4、我们可以在任务管理器中查看是否成功添加开机启动项…

    2022年10月26日
  • mysql opkg源_opkg包管理工具常用命令[通俗易懂]

    mysql opkg源_opkg包管理工具常用命令[通俗易懂]Opkg是一个轻量快速的套件管理系统,目前已成为Opensource界嵌入式系统标准。常用于路由、交换机等嵌入式设备中,用来管理软件包的安装升级与下载。常用命令opkgupdate更新可以获取的软件包列表opkgupgrade对已经安装的软件包升级opkglist获取软件列表opkginstall安装指定的软件包opkgremove卸载已经安装的指定的软件包安装要安装软件…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号