代码生成器的实现与使用

开篇

      本篇主要介绍如何使用现有的技术而不是使用AgileEAS.NET应用开发平台自带的ORM设计器,而是我们实现自己的代码生成器一步一步的。希望大家能在学习的

过程中对代码生成器本身有个更深入的认识与了解,本人技术水平有限,本篇只是抛砖引玉,错误之处,还请大家批评支出。

序言

      代码生成器主要的目的,是适应我们自己的已有框架的编码格式,生成我们需要的基础代码。虽然目前开源的代码生成器也比较多,但是有时候我们自己已有一个

比较成熟的,易用的,快速的稳定的开发框架,这时候写个自定义的代码生成器就极其必要。代码生成器的主要目标是根据数据库表结构生成实体层与数据层代码,当

然具体的业务代码可能还要自己手动来做,代码生成器只能生成基本的增删修查的业务代码。

开始构建

      一般情况下我们的代码生成器首先需要与数据库进行关联,或者是从自定义格式文件中动态的读取实体信息。我们从简单的开始吧。我们本篇都已数据库的链接为

例构建简单的代码代码生成器。首先需要一个简单的数据库链接的配置页面,配置文件可以直接通过XML文件来存储,或者不构建这样的可视化的配置界面,直接通过

XML文件来实现。

     由于本篇意在指导大家来做,所以这里就直接通过XML来配置数据库访问字符串。

<?xml version="1.0" encoding="utf-8" ?>
<Connection>
  <ConnectionItem name="ConnectionString"  type="SQLServer">Data Source=.\SQLEXPRESS;Initial Catalog=EasyStore;User ID=es;Password=123456</ConnectionItem>
  <ConnectionItem name="ConnectionString1" type="Oracle"></ConnectionItem>
  <ConnectionItem name="ConnectionString2" type="Access"></ConnectionItem>
</Connection>

    首先是根据XML配置文件中读取链接字符串,读取ConnectionString,然后与数据建立链接。

    主要代码如下:

     该类负责读取XML文档中节点的值

     public class ConfigXml
    {
        public static ConfigXml instance;
        public static ConfigXml Instance
        {
            get
            {
                if (instance == null)
                    instance = new ConfigXml();
                return instance;
            }
        }

        public string GetConnectionString(string filename, string type)
        {
            string value = string.Empty;

            string path = System.IO.Directory.GetCurrentDirectory().Replace("\\bin", "") + "/CommonLibary/" + filename + ".xml";

            XmlDocument doc = new XmlDocument();
            doc.Load(path);

            XmlElement root = doc.DocumentElement;

            XmlNodeList nodes = root.SelectNodes("ConnectionItem");

            foreach (XmlNode node in nodes)
            {
                XmlElement ele = (XmlElement)node;

                if (ele.GetAttribute("type") == type)
                {
                    value = ele.InnerText;
                }
            }

            return value;
        }
    }

   

    通过这个类文件就可以读取出链接字符串,接下来就是在具体生成代码的主界面中通过这个类提供的方法,从数据库中读取出所有的该数据库下的所有的表,绑定在树形列表中:

     private string connectionString = @"" + ConfigXml.Instance.GetConnectionString("ConfigXmlPath", "SQLServer") + "";

      public OfficeWordCreator()
        {
            InitializeComponent();
            this.InitInfo();
        }

        private void InitInfo()
        {
            SqlAccess sql = new SqlAccess();

            string sqlText  = " SELECT A.NAME,B.NAME OWNER FROM SYSOBJECTS A LEFT JOIN SYSUSERS B ON A.UID = B.UID  WHERE A.TYPE = 'U' AND A.NAME<>'dtproperties'  ORDER BY A.NAME";

            sql.ConnectionString = this.connectionString;
            this.InitTreeList(sql.Query(sqlText));
        }

private void InitTreeList(DataTable dataTable)
        {
            TreeNode root = new TreeNode("数据库表", 0, 1);

            foreach (System.Data.DataRow row in dataTable.Rows)
            {
                TreeNode node = new TreeNode(row["name"].ToString(), 2, 3);
                node.Tag = row["name"].ToString();

                root.Nodes.Add(node);
            }

            this.tvwList.Nodes.Add(root);

            this.tvwList.ExpandAll();
        }

       绑定后的效果如图:

       image

       接下来我们的操作可能是选择树形的节点后,自动在右侧显示该表中的数据字段。

private void tvwList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (this.tvwList.SelectedNode == null)
                return;
            if (this.tvwList.SelectedNode.Tag == null)
                return;

            this.tbDbName.Text = this.tvwList.SelectedNode.Tag.ToString();

            StringBuilder sb = new StringBuilder();

            sb.Append(" SELECT ");
            sb.Append("A.NAME,A.COLID,C.NAME TYPE,A.LENGTH BYTES,COLUMNPROPERTY(A.id,A.name,'precision') LENGTH,");
            sb.Append("A.XPREC [PRECISION],ISNULL(COLUMNPROPERTY(A.ID,A.NAME,'Scale'),0) SCALE,ISNULL(D.TEXT,'') DEFAULTVALUE,");
            sb.Append("CASE when exists(SELECT 1 FROM SYSOBJECTS where xtype='PK'and name in (  SELECT NAME FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid  )))     then '1' else '0' END PK,");
            sb.Append("F.NAME TABLE_NAME,F.OWNER TABLE_OWNER ");
            sb.Append("FROM SYSCOLUMNS A LEFT JOIN SYSOBJECTS B ON A.ID = B.ID ");
            sb.Append("LEFT JOIN SYSTYPES C ON A.XTYPE=C.XUSERTYPE ");
            sb.Append("LEFT JOIN SYSCOMMENTS D ON A.CDEFAULT = D.ID ");
            sb.Append("INNER JOIN ");
            sb.Append("(SELECT A.NAME,A.ID,B.NAME OWNER FROM SYSOBJECTS A LEFT JOIN SYSUSERS B ON A.UID = B.UID WHERE A.TYPE = 'U' OR A.TYPE = 'V') F ON A.ID = F.ID ");
            sb.Append(" AND F.NAME='" + this.tbDbName.Text + "' ORDER BY A.COLID");

            string sqlText = sb.ToString();

            SqlAccess access = new SqlAccess();
            access.ConnectionString = this.connectionString;

            this.InitlvwInfo(access.Query(sqlText));
        }

private void InitlvwInfo(DataTable dataTable)
        {
            this.lvwInfo.Items.Clear();
            this.lvwInfo.BeginUpdate();

            foreach (System.Data.DataRow row in dataTable.Rows)
            {
                ListViewItem item = new ListViewItem(new string[] { "", row["name"].ToString(), row["type"].ToString(), row["bytes"].ToString(), row["PK"].ToString() == "1" ? "是" : "否" });
                item.Tag = row;

                this.lvwInfo.Items.Add(item);
            }
            this.lvwInfo.Tag = dataTable;

            this.lvwInfo.EndUpdate();
        }

       通过上面的2个函数即可实现,当选中某个属性节点后,列表中自动显示该表下的所有的列。具体效果如图:

       image

       然后通过选中的字段名称,点击生成文档,然后在不同的文档页面中就生成了不同的代码。

       image

        当然可能生成的代码还有部分错误,这里只是抛砖引玉。为不熟悉这块内容的朋友提供一个简单的认识。

 

源码下载

     如果各位有好的建议还请多多给我提出改进意见。谢谢您的意见。

posted @ 2010-09-08 22:05  hotdefans  阅读(6357)  评论(9编辑  收藏  举报