上一篇文章中,我们分析了系统的两个实体类,并且给出了对应的实体XML。今天我们来看看如何根据这个XML进行代码生成。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <Entities xmlns="http://it.ouc.edu.cn/EntityDescription/V2">
3: <Entity title="日志" name="Blog" module="Blogs">
4: <Item title="标题" name="Title" type="text" require="true"/>
5: <Item title="内容" name="Content" type="longtext" require="false"/>
6: <Item title="所属分类" name="BlogClass" type="entity" entityName="BlogClass" require="false"/>
7: <Item title="创建时间" name="CreateDateTime" type="datetime" require="true"/>
8: <Item title="更新时间" name="UpdateDateTime" type="datetime" require="true"/>
9: </Entity>
10: <Entity title="日志分类" name="BlogClass" module="Blogs">
11: <Item title="名称" name="Name" type="text" require="true"/>
12: <Item title="描述" name="Description" type="text" require="false"/>
13: </Entity>
14: </Entities>
这里我们主要是生成两种最重要的代码,一是数据库的建库脚本,二是实体的CS类。
我们使用测试来驱动代码生成,在项目DongBlog.Test中添加一个新的单元测试:Util.cs。对应的代码如下:
1: using ...
  12:   13: namespace DongBlog.Test
  14:  {15: /// <summary>
16: /// 数据库相关的工具方法
17: /// </summary>
  18:      [TestClass]19: public class DatabaseUtil
  20:      {21: /// <summary>
22: /// 构造建库脚本
23: /// </summary>
24: [TestMethod, Description("构造建库脚本")]
25: public void Util_CreateDatabaseScript()
  26:          {  27:              var entities = getEntities();28: string sqlText = MsSqlServerScriptBuilder.getSqlScript(entities);
  29:   30: Debug.WriteLine("");
31: Debug.WriteLine("The following is the database creating script:");
32: Debug.WriteLine("=============================彪悍的分割线==============================================================================");
33: Debug.WriteLine("");
34: Debug.WriteLine("");
  35:              Debug.WriteLine(sqlText);36: Debug.WriteLine("");
37: Debug.WriteLine("");
38: Debug.WriteLine("=============================又见彪悍的分割线==========================================================================");
  39:          }  40:   41: private Entity[] getEntities()
  42:          {43: XmlDocument document = new XmlDocument();
  44:              document.Load(Gobal.EntityXmlFileName);45: return EntityXmlParser.ParseXml(document);
  46:          }  47:      }  48:  }这个类中定义的个单元测试,并不测试任何功能代码,而是用于生成数据库的建库脚本。VS.Net中似乎没有Make这样的自动化脚本,使用第三方的组件和工具则略显繁琐,而这种单元测试的“歪用”能起到不错的效果。:)
单元测试充当自动化脚本还可以实现很多功能,常用的除了上面的生成数据库脚本外,还有生成实体类代码、生成Linq的外置XML映射文件、填充测试数据、从旧版本系统中导入数据、统计代码行数等,大家可以尽情的发挥想象,呵呵。
回到我们的系统中,使用Debug的方式运行Util_CreateDatabaseScript测试,数据库脚本会写入到Output窗口中(使用快捷键Ctrl+W、O打开)。
1: if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_Blog_BlogClass]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
2: ALTER TABLE [dbo].[Blog] DROP CONSTRAINT FK_Blog_BlogClass
3: GO
   4:   5: if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Blog]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
6: drop table [dbo].[Blog]
7: GO
   8:   9: if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[BlogClass]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
10: drop table [dbo].[BlogClass]
11: GO
  12:   13: CREATE TABLE [dbo].[Blog] (
14: [ID] [int] IDENTITY (1, 1) NOT NULL ,
15: [Title] [nvarchar] (255) COLLATE Chinese_PRC_CI_AS NOT NULL ,
16: [Content] [text] COLLATE Chinese_PRC_CI_AS ,
17: [BlogClassID] [int] ,
18: [CreateDateTime] [datetime] NOT NULL ,
19: [UpdateDateTime] [datetime] NOT NULL ,
20: [TimeStamp] [timestamp] NULL
21: ) ON [PRIMARY]
22: GO
  23:   24: CREATE TABLE [dbo].[BlogClass] (
25: [ID] [int] IDENTITY (1, 1) NOT NULL ,
26: [Name] [nvarchar] (255) COLLATE Chinese_PRC_CI_AS NOT NULL ,
27: [Description] [nvarchar] (255) COLLATE Chinese_PRC_CI_AS ,
28: [TimeStamp] [timestamp] NULL
29: ) ON [PRIMARY]
30: GO
  31:   32: ALTER TABLE [dbo].[Blog] WITH NOCHECK ADD
33: CONSTRAINT [PK_Blog] PRIMARY KEY CLUSTERED
  34:      (  35:          [ID]36: ) ON [PRIMARY]
37: GO
38: ALTER TABLE [dbo].[BlogClass] WITH NOCHECK ADD
39: CONSTRAINT [PK_BlogClass] PRIMARY KEY CLUSTERED
  40:      (  41:          [ID]42: ) ON [PRIMARY]
43: GO
44: ALTER TABLE [dbo].[Blog] WITH NOCHECK ADD
45: CONSTRAINT [FK_Blog_BlogClass] FOREIGN KEY
  46:      (  47:          [BlogClassID]48: ) REFERENCES [dbo].[BlogClass] (
  49:          [ID]  50:      )   51:  GO这里数据库脚本的生成借鉴了ROR的一些优点,比如为每个实体添加ID主键和时间戳。另外,实体数据字段类型对应到了具体的数据库类型(bool->bit,text->nvarchar(255)等),而实体间关系对应到表间关系。至于具体的对应规则和生成方式,可以根据项目和所采用数据库的不同进行调整。
自动化的优点就在于,每次我们修改实体XML后,只要重新生成一遍数据库脚本,就可以完成数据库的更新,这点在团队开发中很有用,任何人修改数据库都只需要通知同伴更新一下即可。而在项目每一轮迭代完成、进行发布的时候,也可以方便的获取数据库脚本。
生成器的代码在YD.Data.EntityPrase和YD.Data.DatabaseScriptGenerater这两个命名空间下。很简单,无非是拼字符串而已,大家可以参考一下,根据自己的需要编写自己的生成器(我一直认为编写代码生成工具是程序员的基本功)。
下一篇文章我们将研究怎么生成实体类以及要生成什么样的实体类。
 
                    
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号