代码生成器原理及示例

在三层架构中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%。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 用C语言进行Windows编程入门

    用C语言进行Windows编程入门用C语言进行Windows编程入门本文对一般教程或网上有的(如C语言语法等基础)不深入介绍,对初学者易造成疑惑误解或难以找到的内容进行较详尽的介绍。学习C语言很久了,一直面对控制台应用程序(Win32ConsoleApplication),没有漂亮的界面,是不是不爽呀。用C开发图形界面程序,有多种技术方案,本文希望用简单的例子,深入浅出的介绍一种方案——用C和SDK进行图形界面编程。…

    2022年6月18日
    21
  • java编译命令用什么写_要编译java程序需要使用的命令是什么[通俗易懂]

    java编译命令用什么写_要编译java程序需要使用的命令是什么[通俗易懂]要编译java程序需要使用的命令是什么发布时间:2020-07-2214:01:15来源:亿速云阅读:83作者:Leah要编译java程序需要使用的命令是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。编译java程序需要使用javac命令。使用方法是:1、打开命令提示符,进入到Java文件所在目录下;2、执行【j…

    2022年7月9日
    17
  • fastDB_最近使用

    fastDB_最近使用fastdb的官网fastdb怎么在Linux上面安装?$su-$cd/usr/local/src$wgethttp://www.garret.ru/fastdb-3.76.tar

    2022年8月2日
    6
  • coverletter

    coverletterhttp://www.sohu.com/a/251335322_100216045

    2022年4月28日
    36
  • c语言交通灯简单编程_在第一个交通灯处左转的英文

    c语言交通灯简单编程_在第一个交通灯处左转的英文内容介绍原文档由会员½ӨӨ发布交通灯控制系统设计1万字32页包括程序代码,系统原理图,Proteus仿真过程摘要本设计是交通信号灯控制系统,随着社会的不断的进步,社会的不断发展。交通也日渐复杂,交通的自动化也不断更新,交通的一些指挥系统光靠人来完成是远远不够的,这就需要设计各种交通指挥自动化系统来完成这些复杂的工作。从而使交通指挥系统更加有秩序,更加安全。至此本人设计了交通信号灯控制系统,来…

    2022年9月16日
    0
  • hdu 2159 FATE

    hdu 2159 FATE

    2022年1月6日
    39

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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