软件开发模式——三层架构
此文章需要在读懂 以上这篇架构模式的基础上再继续往下深入学习简化
目录
1.前言
2.框架准备
3 .coboBox的数据绑定
4.创建文件夹
5.工具方法
6.生成一个数据库访问助手类SqlHelper
7.生成模型层Model
8.生成数据访问层DAL层
9.生成业务逻辑层BLL层
10.config配置文件的连接字符串
11.生成按钮调用方法执行生成操作
在你们学习了三层架构开发模式之后,一定知道这三层中需要写 数据表的实体类对象,数据访问层的对应语句以及业务逻辑层的条件处理,对于一些简单的单个数据表来说工作量可能不算大,可是如果需要使用的项目是一种大型数据库的话处理起来的代码量就十分庞大了,由此我们可以给自己偷个懒,但是前提是这种自身的基础够扎实哦,废话不多说,下面步入正题.
目标框架:.NET Framework 4.7.2 (作者制作时学习的框架版本)
输出类型:windows应用程序
界面采用一个Form主窗体 ,三个TextBox文本框,一个comboBox下拉项框和一个触发点击事件的按钮.
文本框的初始值可以设置为你目前自己电脑的数据库的服务器名,用户名和密码
简单的设置textBox的text属性,你能看到这一步相信这种简单的步骤就不需要我详细说怎么设置了吧
这个下拉框的绑定方法采用 comboBox1_DropDown当下拉列表框(ComboBox)的下拉列表部分展开时触发的事件
可能有些人会问到为什么不在load事件程序加载时直接绑定?
因为这个下拉框的值绑定需要访问到数据库,所以就用得上与数据库进行交互,有些小伙伴的文本框不一定会给到初始值所以考虑到这一点才采用DropDpwn下拉部分展示时才触发。
//全局变量
string strsql="";
//路径,后续需要用到的
string path = "";
//数据库连接
public SqlConnection conn = null;
//下拉框展开触发事件
private void comboBox1_DropDown(object sender, EventArgs e)
{
//通过文本框采集的信息拼装成访问数据库连接字符串
strsql = $"server={textBox1.Text};uid={textBox2.Text};pwd={textBox3.Text};database=master";
//需要使用的查询语句 sys.databases 查询所有的数据库
string sql = "select * from sys.databases";
//异常处理
try
{
//创建数据库连接
conn = new SqlConnection(strsql);
//打开数据库连接
conn.Open();
//对当前数据库执行一条T-SQL语句
SqlCommand com = new SqlCommand(sql, conn);
//返回一个读取器
SqlDataReader red = com.ExecuteReader();
//创建一个list集合来接收数据库名字
List list = new List();
//循环读取器将查询到的数据库名添加到list集合中
while (red.Read())
{
list.Add(red["name"].ToString());
}
//关闭数据库连接
conn.Close();
//设置下拉框的显示源
comboBox1.DataSource = list;
//控件使用数据源对象的 name 属性作为显示文本
comboBox1.DisplayMember = "name";
}
catch (Exception)
{
//发生异常的提示信息
MessageBox.Show("发生错误了,请检查用户名或密码是否正确!");
}
}
到这一步我们的下拉框控件的数据就会在点击下拉框展开时显示所有的数据库名称
接下来我们进入复杂的生成按钮
在点击生成的时候我们的数据库可能会有多张表和视图,统一的后缀为.cs,我们这个时候就需要使用一个文件夹来将生成的各个层来区分开来,不然全部散落在一堆视觉效果上就不美观
//创建文件夹的方法
//参数1:表名 参数2:写入文件的内容 参数3:文件夹名 参数4:表名层后缀
public void CreateFile(string tableName,string msg,string dirName,string ex)
{
//判断拼接路径上的文件夹是否存在,不存在重新创建文件夹
if (!Directory.Exists(path + "\\" + dirName))
{
Directory.CreateDirectory(path + "\\" + dirName);
}
//创建一个新文件 path + firname 路径 后面为拼接的文件名 最后加后缀
StreamWriter sw=new StreamWriter(path + "\\" + dirName+"\\"+tableName+ex+".cs");
//写入内容
sw.Write(msg);
sw.Close();
}
//生成按钮的点击事件
private void button1_Click(object sender, EventArgs e)
{
try
{
//下拉框选项不为空
if (!string.IsNullOrEmpty(comboBox1.Text))
{
//弹窗提示用户选择文件路径
FolderBrowserDialog fbd = new FolderBrowserDialog();
//获取文件对话框的返回值
DialogResult ds = fbd.ShowDialog();
//用户选择了路径地址
if (ds == DialogResult.OK)
{
//将选中的路径赋值给全局变量
path = fbd.SelectedPath;
//执行生成文件的方法........(先行省略)
//弹窗提示成功
MessageBox.Show("生成成功!");
}
}
else { MessageBox.Show("你不选数据库该让我怎么工作?"); }
}
catch (Exception ex)
{
MessageBox.Show("发生错误:"+ex.Message);
}
}
后续点击事件获取路径后,接下来会补全文件生成的方法
在选中需要生成的数据库的时候,获取当前数据库的所有表名和视图名:
//返回一个list集合
public List GetTableNames()
{
//连接字符串相比comboBox的只修改了一个当前选中的数据库
strsql = $"server={textBox1.Text};uid={textBox2.Text};pwd={textBox3.Text};database={comboBox1.Text}";
conn = new SqlConnection(strsql);
conn.Open();
//查询语句为查询数据库中的所有对象 条件:类型为表或视图
string sql = "select * from sys.objects where type='V' or type='U'";
SqlCommand com=new SqlCommand(sql, conn);
SqlDataReader red = com.ExecuteReader();
List list= new List();
while (red.Read())
{
list.Add(red["name"].ToString());
}
conn.Close();
//表名和视图名添加到list集合后return返回出
return list;
}
这个方法会查询选中的数据库中的所有对象(再通过where条件筛选出表和视图),而后通过list集合存储所有的的视图和表名,最后再返回这个集合
SqlHelper类用于简化在 C# 中与数据库进行交互的操作。它封装了一些常用的数据库操作方法,例如执行查询、执行非查询、执行存储过程等。
以下提供一个常规的类源码:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DAL
{
///
/// 数据库辅助类
///
class SqlHelper
{
//连接字符串
static string conStr = System.Configuration.ConfigurationManager.ConnectionStrings["stuDB"].ToString();
#region 增、删、改
///
/// 增、删、改(普通sql语句)
///
/// 普通sql语句
/// 受影响行数
public static int CUD(string sql)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
int result = com.ExecuteNonQuery();
return result;
}
catch (Exception ex)
{
return -1;
}
finally
{
conn.Close();
}
}
#endregion
#region 增、删、改(参数化的sql语句)
///
/// 增、删、改(参数化的sql语句)
///
/// 带@参数的sql语句
/// 存储SqlParameter对象的集合
/// 受影响行数
public static int CUD(string sql, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
com.Parameters.AddRange(sqlParams.ToArray());//ToArray()用于将集合转换为数组
int result = com.ExecuteNonQuery();
return result;
}
catch (Exception ex)
{
return -1;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行查询操作,返回SqlDataReader对象
///
/// 执行查询操作,返回SqlDataReader对象
///
/// 普通sql语句
/// SqlDataReader对象
public static SqlDataReader GetReader(string sql)
{
try
{
SqlConnection conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
SqlDataReader sdr = com.ExecuteReader(CommandBehavior.CloseConnection);//CommandBehavior.CloseConnection用于设置当SqlDataReader关闭时会自动关闭连接
return sdr;
}
catch (Exception ex)
{
return null;
}
}
#endregion
#region 执行查询操作,返回SqlDataReader对象(参数化的sql语句)
///
/// 执行查询操作,返回SqlDataReader对象(参数化的sql语句)
///
/// 带@参数的sql语句
/// 存储SqlParameter对象的集合
/// SqlDataReader对象
public static SqlDataReader GetReader(string sql, List sqlParams)
{
try
{
SqlConnection conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
com.Parameters.AddRange(sqlParams.ToArray());
SqlDataReader sdr = com.ExecuteReader(CommandBehavior.CloseConnection);//CommandBehavior.CloseConnection用于设置当SqlDataReader关闭时会自动关闭连接
return sdr;
}
catch (Exception ex)
{
return null;
}
}
#endregion
#region 执行查询操作,返回DataTable对象
///
/// 执行查询操作,返回DataTable对象
///
/// 普通sql语句
/// 返回DataTable
public static DataTable GetDataTable(string sql)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlDataAdapter sda = new SqlDataAdapter(sql, conn);
DataTable table = new DataTable();
sda.Fill(table);
return table;
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行查询操作,返回DataTable对象(参数化sql语句)
///
/// 执行查询操作,返回DataTable对象(参数化sql语句)
///
/// 带@参数的sql语句
/// 存储SqlParameter对象的集合
/// 返回DataTable
public static DataTable GetDataTable(string sql, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlDataAdapter sda = new SqlDataAdapter();
SqlCommand com = new SqlCommand(sql, conn);
com.Parameters.AddRange(sqlParams.ToArray());
sda.SelectCommand = com;
DataTable table = new DataTable();
sda.Fill(table);
return table;
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行查询语句,返回第一行第一个单元格中的数据
///
/// 执行查询语句,返回第一行第一个单元格中的数据
///
/// 普通sql语句
/// 返回第一行第一个单元格中的数据
public static object GetScalar(string sql)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
object result = com.ExecuteScalar();
return result;
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行查询语句,返回第一行第一个单元格中的数据(参数化的sql语句)
///
/// 执行查询语句,返回第一行第一个单元格中的数据(参数化的sql语句)
///
/// 带@参数的sql语句
/// 存储SqlParameter对象的集合
/// 返回第一行第一个单元格中的数据
public static object GetScalar(string sql, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
com.Parameters.AddRange(sqlParams.ToArray());
object result = com.ExecuteScalar();
return result;
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行存储过程返回DataTable
///
/// 执行存储过程返回DataTable
///
/// 存储过程名称
/// 参数集合
/// DataTable
public DataTable ProcDataTable(string procName, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlDataAdapter sda = new SqlDataAdapter();
SqlCommand com = new SqlCommand(procName, conn);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddRange(sqlParams.ToArray());
sda.SelectCommand = com;
DataTable table = new DataTable();
sda.Fill(table);
return table;
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行存储过程返回受影响行数
///
/// 执行存储过程返回受影响行数
///
/// 存储过程名称
/// 参数集合
/// 受影响行数
public static int ProcCUD(string procName, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(procName, conn);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddRange(sqlParams.ToArray());
int result = com.ExecuteNonQuery();
return result;
}
catch (Exception ex)
{
return -1;
}
finally
{
conn.Close();
}
}
#endregion
#region 执行存储过程,获取输出参数的结果
///
/// 执行存储过程,获取输出参数的结果
///
/// 存储过程名称
/// 参数集合
///
public string ExecProc(string procName, List sqlParams)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection(conStr);
conn.Open();
SqlCommand com = new SqlCommand(procName, conn);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddRange(sqlParams.ToArray());
com.ExecuteNonQuery();
string result = com.Parameters["@Ret_Msg"].Value.ToString();
return result;
}
catch (Exception)
{
return null;
}
finally
{
conn.Close();
}
}
#endregion
}
}
常规的操作增删改的返回值全都是受影响行数为一个int类型的返回值不同点在于sql语句不同,sql语句的编写就可以抛出到DAL层去编写
查询语句返回尽可能是一个读取器,或datatable的表数据
以上的方法也区别于普通的方法和参数化命令的方法
接下来在生成器的后台中新建一个方法用于在DAL层生成一个数据访问助手类:
public void CreateSqlHelper()
{
StringBuilder sb = new StringBuilder();
//将上面的代码段复制追加到可变字符串
sb.Append("using System;\r\nusing System.Collections.Generic;\r\nusing System.Data;\r\nusing System.Data.SqlClient;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace DAL\r\n{\r\n /// \r\n /// 数据库辅助类\r\n /// \r\n class SqlHelper\r\n {\r\n //连接字符串\r\n static string conStr = System.Configuration.ConfigurationManager.ConnectionStrings[\"stuDB\"].ToString();\r\n\r\n #region 增、删、改\r\n /// \r\n /// 增、删、改(普通sql语句)\r\n /// \r\n /// 普通sql语句\r\n /// 受影响行数 \r\n public static int CUD(string sql)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n int result = com.ExecuteNonQuery();\r\n return result;\r\n }\r\n catch (Exception ex)\r\n {\r\n return -1;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion \r\n\r\n #region 增、删、改(参数化的sql语句)\r\n /// \r\n /// 增、删、改(参数化的sql语句)\r\n /// \r\n /// 带@参数的sql语句\r\n /// 存储SqlParameter对象的集合\r\n /// 受影响行数 \r\n public static int CUD(string sql, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n com.Parameters.AddRange(sqlParams.ToArray());//ToArray()用于将集合转换为数组\r\n int result = com.ExecuteNonQuery();\r\n return result;\r\n }\r\n catch (Exception ex)\r\n {\r\n return -1;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行查询操作,返回SqlDataReader对象\r\n /// \r\n /// 执行查询操作,返回SqlDataReader对象\r\n /// \r\n /// 普通sql语句\r\n /// SqlDataReader对象 \r\n public static SqlDataReader GetReader(string sql)\r\n {\r\n try\r\n {\r\n SqlConnection conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n SqlDataReader sdr = com.ExecuteReader(CommandBehavior.CloseConnection);//CommandBehavior.CloseConnection用于设置当SqlDataReader关闭时会自动关闭连接\r\n return sdr;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n }\r\n #endregion\r\n\r\n #region 执行查询操作,返回SqlDataReader对象(参数化的sql语句)\r\n /// \r\n /// 执行查询操作,返回SqlDataReader对象(参数化的sql语句)\r\n /// \r\n /// 带@参数的sql语句\r\n /// 存储SqlParameter对象的集合\r\n /// SqlDataReader对象 \r\n public static SqlDataReader GetReader(string sql, List sqlParams)\r\n {\r\n try\r\n {\r\n SqlConnection conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n SqlDataReader sdr = com.ExecuteReader(CommandBehavior.CloseConnection);//CommandBehavior.CloseConnection用于设置当SqlDataReader关闭时会自动关闭连接\r\n return sdr;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行查询操作,返回DataTable对象\r\n /// \r\n /// 执行查询操作,返回DataTable对象\r\n /// \r\n /// 普通sql语句\r\n /// 返回DataTable \r\n public static DataTable GetDataTable(string sql)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlDataAdapter sda = new SqlDataAdapter(sql, conn);\r\n DataTable table = new DataTable();\r\n sda.Fill(table);\r\n return table;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n }\r\n #endregion\r\n\r\n #region 执行查询操作,返回DataTable对象(参数化sql语句)\r\n /// \r\n /// 执行查询操作,返回DataTable对象(参数化sql语句)\r\n /// \r\n /// 带@参数的sql语句\r\n /// 存储SqlParameter对象的集合\r\n /// 返回DataTable \r\n public static DataTable GetDataTable(string sql, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlDataAdapter sda = new SqlDataAdapter();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n sda.SelectCommand = com;\r\n DataTable table = new DataTable();\r\n sda.Fill(table);\r\n return table;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行查询语句,返回第一行第一个单元格中的数据\r\n /// \r\n /// 执行查询语句,返回第一行第一个单元格中的数据\r\n /// \r\n /// 普通sql语句\r\n /// 返回第一行第一个单元格中的数据 \r\n public static object GetScalar(string sql)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n object result = com.ExecuteScalar();\r\n return result;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n }\r\n #endregion\r\n\r\n #region 执行查询语句,返回第一行第一个单元格中的数据(参数化的sql语句)\r\n /// \r\n /// 执行查询语句,返回第一行第一个单元格中的数据(参数化的sql语句)\r\n /// \r\n /// 带@参数的sql语句\r\n /// 存储SqlParameter对象的集合\r\n /// 返回第一行第一个单元格中的数据 \r\n public static object GetScalar(string sql, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(sql, conn);\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n object result = com.ExecuteScalar();\r\n return result;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行存储过程返回DataTable\r\n /// \r\n /// 执行存储过程返回DataTable\r\n /// \r\n /// 存储过程名称\r\n /// 参数集合\r\n /// DataTable \r\n public DataTable ProcDataTable(string procName, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlDataAdapter sda = new SqlDataAdapter();\r\n SqlCommand com = new SqlCommand(procName, conn);\r\n com.CommandType = CommandType.StoredProcedure;\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n sda.SelectCommand = com;\r\n DataTable table = new DataTable();\r\n sda.Fill(table);\r\n return table;\r\n }\r\n catch (Exception ex)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行存储过程返回受影响行数\r\n /// \r\n /// 执行存储过程返回受影响行数\r\n /// \r\n /// 存储过程名称\r\n /// 参数集合\r\n /// 受影响行数 \r\n public static int ProcCUD(string procName, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(procName, conn);\r\n com.CommandType = CommandType.StoredProcedure;\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n int result = com.ExecuteNonQuery();\r\n return result;\r\n }\r\n catch (Exception ex)\r\n {\r\n return -1;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n\r\n #region 执行存储过程,获取输出参数的结果\r\n /// \r\n /// 执行存储过程,获取输出参数的结果\r\n /// \r\n /// 存储过程名称\r\n /// 参数集合\r\n /// \r\n public string ExecProc(string procName, List sqlParams)\r\n {\r\n SqlConnection conn = null;\r\n try\r\n {\r\n conn = new SqlConnection(conStr);\r\n conn.Open();\r\n SqlCommand com = new SqlCommand(procName, conn);\r\n com.CommandType = CommandType.StoredProcedure;\r\n com.Parameters.AddRange(sqlParams.ToArray());\r\n com.ExecuteNonQuery();\r\n string result = com.Parameters[\"@Ret_Msg\"].Value.ToString();\r\n return result;\r\n }\r\n catch (Exception)\r\n {\r\n return null;\r\n }\r\n finally\r\n {\r\n conn.Close();\r\n }\r\n } \r\n #endregion\r\n }\r\n}\r\n");
//调用方法创建文件
CreateFile("SqlHelper", sb.ToString(), "DAL", "");
}
上一步的方法已经得到了当前数据库的所有表以及视图名称,有了现有条件之后就可以进行下一步操作了:获取所有表的列名以及数据类型
public void CreateModel()
{
//调用上一步的工具方法获取所有表和视图的name
List list =GetTableNames();
//拼接数据库访问语句
strsql = $"server={textBox1.Text};uid={textBox2.Text};pwd={textBox3.Text};database={comboBox1.Text}";
//循环list所有表名
foreach(string tableName in list)
{
//创建一个可变字符串
StringBuilder sb = new StringBuilder();
//追加字符串:为一个类文件的无变量基本数据格式
sb.Append("using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace Model\r\n{\r\n public class {tablename}:ModelBase\r\n {\r\n {cols}\r\n }\r\n}");
conn = new SqlConnection(strsql);
conn.Open();
//当前循环的表所有数据查询
string sql = "select * from " + tableName;
SqlCommand com = new SqlCommand(sql,conn);
//设置只查询列名和主键信息 用datatable接收
DataTable dt=com.ExecuteReader(CommandBehavior.KeyInfo).GetSchemaTable();
//循环内新建一个可变字符串
StringBuilder sul=new StringBuilder();
//循环datatable的列
for (int i = 0; i < dt.Rows.Count; i++)
{
//获取列名和数据类型
string col = dt.Rows[i]["ColumnName"].ToString();
string datatype = dt.Rows[i]["DataType"].ToString();
拼装成公有变量字符串追加到sul字符串中
sul.Append("public "+datatype+" "+col+"{ get; set; }"+"\n\n\t\t");
}
conn.Close();
//替换sb字符串的指定部分
sb.Replace("{tablename}", tableName).Replace("{cols}", sul.ToString());
//将处理过后的文本内容写入文件夹
CreateFile(tableName, sb.ToString(), "Model", "");
}
}
CreateModel()方法会通过循环GatTableNames()方法获取的指定的数据库中所有视图以及表的名字,再通过循环查询每一个视图或表的列名和数据类型拼接成公有变量,再替换到文本格式中生成一个类文件,最后再通过CreateFile()方法写入到指定文件夹
有了模型层后接下来编写新建DAL层的方法,也是通过获取到对应数据库表名的方法为核心来做IO流的操作:
public void CreateDAL()
{ //获取所有视图和表
List list = GetTableNames();
foreach (string tableName in list)
{
//BAL要写出的类的模板
StringBuilder sb = new StringBuilder();
//追加一个初步没有返回值的方法
sb.Append("using Model;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Data.SqlClient;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace DAL\r\n{\r\n public class {tableName}DAL\r\n {\r\n public List<{tableName}> SelectAll()\r\n {\r\n return null;\r\n }\r\n\r\n public int Insert({tableName} info)\r\n {\r\n return 0;\r\n }\r\n\r\n public int DeleteForKey(object key)\r\n {\r\n return 0;\r\n }\r\n\r\n public {tableName} SelectForKey(object key)\r\n {\r\n return null;\r\n }\r\n\r\n public int Update({tableName} info)\r\n {\r\n return 0;\r\n }\r\n }\r\n}");
//替换占位内容 修改为当前循环的表名
sb.Replace("{tableName}", tableName);
//调用方法创建文件 生成的文件名为表名DAL.cs
CreateFile(tableName, sb.ToString(), "DAL", "DAL");
}
//创建一个SqlHelper
CreateSqlHelper();
}
这个方法所生成的方法返回值都是空值或0,需要后续自己手动写Sql语句和返回值处理。
目前这个版本需要自己手动写DAL层的方法,后续更新可以通过反射原理来补全
最后的一个文件夹BLL业务逻辑层,原理同DAL层相似:
using Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DAL;
namespace BLL
{
//引用对应的DAL层的方法 (BLL模板)
public class {tableName}BLL
{
{tableName}DAL dal=new {tableName}DAL();
public List<{tableName}> SelectAll()
{
return dal.SelectAll();
}
public int Insert({tableName} info)
{
return dal.Insert(info);
}
public int DeleteForKey(object key)
{
return dal.DeleteForKey(key);
}
public {tableName} SelectForKey(object key)
{
return dal.SelectForKey(key);
}
public int Update({tableName} info)
{
return dal.Update(info);
}
}
}
//创建BLL层的方法
public void CreateBLL()
{
//直接循环GetTableNames()返回的集合
foreach(string tableName in GetTableNames())
{
创建可变字符串
StringBuilder sb = new StringBuilder();
//追加BLL模板
sb.Append("using Model;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Data.SqlClient;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing DAL;\r\n\r\nnamespace BLL\r\n{\r\n public class {tableName}BLL\r\n {\r\n {tableName}DAL dal=new {tableName}DAL();\r\n /// \r\n /// 整表查询\r\n /// \r\n /// \r\n public List<{tableName}> SelectAll()\r\n {\r\n return dal.SelectAll();\r\n }\r\n /// \r\n /// 通用添加方法\r\n /// \r\n /// 实体类\r\n /// 返回受影响行数 \r\n public int Insert({tableName} info)\r\n {\r\n return dal.Insert(info);\r\n }\r\n /// \r\n /// 主键条件删除\r\n /// \r\n /// 主键编号\r\n /// 返回受影响行数 \r\n public int DeleteForKey(object key)\r\n {\r\n return dal.DeleteForKey(key);\r\n }\r\n /// \r\n /// 单条数据查询\r\n /// \r\n /// 主键编号\r\n /// 返回实体类 \r\n public {tableName} SelectForKey(object key)\r\n {\r\n return dal.SelectForKey(key);\r\n }\r\n /// \r\n /// 条件组合查询\r\n /// \r\n /// \r\n /// \r\n public List<{tableName}> SelectWhere(object obj)\r\n {\r\n string sqlwhere = \"\";\r\n return dal.SelectWhere(sqlwhere);\r\n }\r\n /// \r\n /// 通用修改方法\r\n /// \r\n /// \r\n /// \r\n public int Update({tableName} info)\r\n {\r\n return dal.Update(info);\r\n }\r\n }\r\n}");
//替换占位内容
sb.Replace("{tableName}", tableName);
//创建文件
CreateFile(tableName,sb.ToString(),"BLL","BLL");
}
}
生成的BLL层只有调用DAL层数据访问方法的对应方法,可以在这层自行改动对UI层传输来的数据进行二次处理和判断
这一步就是将打开数据库的语句自动生成一下,也就是下面这句话:
"server={textBox1.Text};uid={textBox2.Text};pwd={textBox3.Text};database={comboBox.Text}"
这句话写在config配置文件中的代码量也是比较少的,但是作者想偷懒就单独做了一个方法生成
朋友们觉得多余可以不用看这一步
//创建连接字符串
public string appconfig()
{
//新建一个可变字符串
StringBuilder sb=new StringBuilder();
//追加链接字符串模板
sb.Append("\r\n\t\t\r\n\t ");
//将当前的窗体中的数据替换到字符串中
sb.Replace("{server}", textBox1.Text).Replace("{uid}", textBox2.Text).Replace("{pwd}",textBox3.Text).Replace("{database}",comboBox1.Text);
return sb.ToString();
}
//重载创建文件方法 生成一个.txt文件
public void CreateFile(string tableName, string msg, string dirName)
{
if (!Directory.Exists(path + "\\" + dirName))
{
Directory.CreateDirectory(path + "\\" + dirName);
}
StreamWriter sw = new StreamWriter(path + "\\" + dirName + "\\" + tableName + ".txt");
sw.Write(msg);
sw.Close();
}
最后一步,各层文件的生成方法现在全部写好了,现在就到了验证的时候了,回到窗体按钮的点击事件中将几个方法调用:
private void button1_Click(object sender, EventArgs e)
{
try
{
if (!string.IsNullOrEmpty(comboBox1.Text))
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult ds = fbd.ShowDialog();
if (ds == DialogResult.OK)
{
path = fbd.SelectedPath;
//创建模型层Model
CreateModel();
//创建数据访问层DAL
CreateDAL();
//创建业务逻辑层BLL
CreateBLL();
//调用重载的生成txt文件的方法生成连接字符串
CreateFile("APP",appconfig(),"");
MessageBox.Show("生成成功!");
}
}
else { MessageBox.Show("你不选数据库该让我怎么工作?"); }
}
catch (Exception ex)
{
MessageBox.Show("发生错误:"+ex.Message);
}
}
到这一步我们的三层架构代码生成器1.0就已经完成了,在接下来的开发中会帮助你们节省部分时间,如果在实操中遇到问题的话可以关注作者私信解决,感兴趣的朋友们可以关注作者,后续更新2.0版本的生成器
2.0的版本会通过继承,使用泛型能使类型参数化从而变得灵活和反射的逻辑来自动拼接sql语句,简化更多代码,节省更多的开发时间,更改的条件是在1.0版本之上,有兴趣的朋友可以自己先行更改。