上一篇文章中,我们分析了系统的两个实体类,并且给出了对应的实体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这两个命名空间下。很简单,无非是拼字符串而已,大家可以参考一下,根据自己的需要编写自己的生成器(我一直认为编写代码生成工具是程序员的基本功)。
下一篇文章我们将研究怎么生成实体类以及要生成什么样的实体类。