使用 NVelocity 解析 PowerDesigner 的cdm文件
使用powerdesign来进行数据库设计应该是设计者的首选了,而且现在的powerdesign做得越来越好,新版的11已经开始可以把实体和需求一一对应了。powerdesign本身还能够支持数据库的创建和修改,如果oom的话也可以生成代码,并且其本身可以支持在cdm,oom,pdm格式之间的相互转换。但是在实际应用中,远远不够。因为很多程序员自己做了很多的架构和规范,powerdesign内置的单一功能的代码生成已经远远不能满足实际使用中的需求。比如想用 hibernate/NHibernate 的朋友们想直接生成 .hbm.xml 文件的话,常规方法只能够是先创建数据库,然后用hbm自己的工具反向生成代码。实际使用中,常常因为实体间多对多的关系,hbm生成的配置文件还要进行修改之后才能使用。
本人也在实际工作中遇到了同样的问题,所以把以前的几个工具综合起来,最终采用了NVelocity(http://sourceforge.net/projects/nvelocity/)来做实际的代码转换工作,我自己编了一个对cdm文件的解释器,提供给NVelocity。然后NVelocity装入我们编写的模版文件,解释并生成代码。
具体NVelocity模版怎么编写,大家可以参考http://jakarta.apache.org/velocity/中的user guide(英文)。另外我提供的工程中还会有一个测试用的小模版,基本的技巧都用到了,也可以作为参考。
我export给NVelocity的入口变量是 $pdm,是一个 PDM 的实例。其中涉及到的各个类的可用成员和解释如下所示。
其中 xxxCollection 都是一个 IList 派生的类型。
另外,这里支持在 对象的 Comment 区域中加入如下格式的自定义配置信息
comment line1
comment line2
comment line n
[config]
name1
=
value1
//
注释
nameN
=
valueN
//
注释 N
从 $pdm 中可以引用到如下的对象:
class
PDM
//
系统的总入口,对应一个pdm文件的所有内容
NamespaceCollection Namespaces
//
pdm中所有的Package
EntityCollection Entities
//
pdm中所有的Entity,
DomainCollection Domains
//
pdm中所有的Domain
DataItemCollection DataItems
//
pdm中所有的DataItem
string
CreatePDMName(
string
name,
int
count)
//
为了方便生成 pdm 的重复名字生成逻辑(属性级),
//
比如 GroupId,Gro_GroupId,Gro_GroupId1等等
string
CreateUniqueName(
string
name,
int
count)
//
为了方便生成类一级的重复名字
class
Namespace
//
对应一个 Package
EntityCollection Entities
//
该Package中的所有Entity
DataItemCollection DataItems
//
该 Package中的所有 DataItem
RelationshipCollection Relationships
//
该Package中的所有Relationship
InheritanceCollection Inheritances
//
所有 Package 中的继承关系
string
Id
//
Package 的 id
string
ObjectId
//
Package 的 GUID
string
Name
//
中文名称,以下所有的 Name 都是相同含义
string
Code
//
代码名称,
PDM Owner
//
对 PDM 的反向引用
Comment Comment
//
Comment内容中"[config]"标志之前的内容
string
GetConfigValue(
string
name)
//
从配置中获取name对应的value,如果不存在则返回空字符串(String.Empty)
class
Entity
//
实体
AttributeCollection Attributes
//
实体中所有的字段
Index PrimaryIndex
//
主索引
IndexCollection Indexs
//
其他索引
DataItemCollection DataItems
//
实体中引用到的 DataItem,应该看作字段类型而不是字段
RelationLinkCollection Relation
//
本实体需要关注的RelationLink,是经过处理了的Relationship
RelationLinkCollection AllRelationships
//
和本实体相关的所有的 Relationship
InheritanceCollection Base
//
所有实体相关的基类继承关系
InheritanceCollection Derives
//
所有实体相关的派生类继承关系
bool
Generated
//
是否要处理
string
Id
//
同上类
string
ObjectId
string
Name
string
Code
Namespace Owner
Comment Comment
//
Comment内容中"[config]"标志之前的内容
string
GetConfigValue(
string
name)
//
从配置中获取name对应的value,如果不存在则返回空字符串(String.Empty)
ArrayList GetBaseList()
//
获取所有的基类实体列表
ArrayList GetDeriveList()
//
获取本实体所有的派生类实体列表
class
DataItem
//
数据项
string
Id
//
同上类
string
ObjectId
string
Name
string
Code
int
Length
//
数据项的长度
DataTypeInfo DataType
//
数据的类型,比如 VA50,I 等等
Domain Domain
//
数据类型相关的 Domain
Namespace Owner
Comment Comment
string
GetConfigValue(
string
name)
class
Attribute
//
Entity 的字段
string
Name
string
Code
DataTypeInfo DataType
bool
CodeExistInBase
//
相同代码的Attribute是否存在于所属实体的基类中
bool
CodeExistInDerives
//
相同代码的Attribute是否存在于所属实体的派生类中
DataItem DataItem
IndexCollection Indexs
//
Attribute 参与的索引集合
Entity Owner
string
Id
string
ObjectId
bool
Mandatory
//
是否必须字段
Comment Comment
//
Comment内容中"[config]"标志之前的内容
string
GetConfigValue(
string
name)
//
从配置中获取name对应的value,如果不存在则返回空字符串(String.Empty)
class
Relationship
//
关系
Entity Object1
Entity Object2
RelationshipEntity RelationEntity
//
为了方便生成中间表,特意把多对多关系的内容提到这里
//
请使用 Pd_NameExt/Pd_NameExts 来获取中间表的字段名
string
Id
string
ObjectId
string
Name
string
Code
string
DominantRole
//
主导方,=A表示Object2要引用Object1,
//
=B则反之,为""则表示都需要,已经处理在 RelationLink 中了,不需要再自行处理
string
DependentRole
//
依赖于哪一方,A表示Object1引用Object2,B反之,为""则都需要
//
同样已经处理在 RelationLink 中了,不需要自行处理
Namespace Owner
Comment Comment
//
Comment内容中"[config]"标志之前的内容
string
GetConfigValue(
string
name)
//
从配置中获取name对应的value,如果不存在则返回空字符串(String.Empty)
class
RelationLink
//
经过处理之后的关系,包含在 Entity.Relation 中,是单方关系
Relationship Relationship
//
相关的Relationship
Entity Owner
//
关系的拥有者
Entity Entity
//
关系引用的 Entity
string
Role
//
关系的名称
Cardinality Cardinality
//
所属Entity和本关系引用的Entity之间的对应关系 1:1,1:n等等
Cardinality ReverseCardinality
//
本关系引用的Entity和所属Entity之间的对应关系 1:1,1:n等等
bool
IsMultiMulti
//
本关系是否多对多关系
RelationLink Pair
//
如果是成对的关系,则指向关系的另一头
string
Pd_Name
//
powerdesign生成的数据库字段名,如引用的Entity有复合主键,则应用Pd_Names
//
如果是多对多关系的话,本名字保持原始引用名,需要用生成名请参考Pd_NameExt,
string
[] Pd_Names
//
复合主键对应的名称
string
UniqueCode
//
为了方便处理而生成的实体中唯一的对象名称
int
UniqueSeed
//
生成UniqueCode和Pd_Name时候使用的count参数
string
GetConfigValue(
string
name)
class
RelationshipEntity
//
多对多关系的中间实体
Relationship Owner
//
所属的关系
string
Name
string
Code
RelationLinkCollection Fields
//
实体包含的所有内容
string
GetConfigValue(
string
name)
//
获取相关的relationship中的配置信息
class
Cardinality
//
对应关系,比如 1:n
string
Min
//
string
Max
class
Index
//
索引
AttributeCollection Attributes
//
索引包含的字段
Entity Owner
string
Id
string
ObjectId
string
Name
string
Code
Comment Comment
//
注释
string
GetConfigValue(
string
name)
//
获取配置值
class
Inheritance
//
继承关系描述
Entity Parent
//
继承关系中的基类实体
EntityCollection Children
//
继承关系中的派生类实体
bool
InheritAll
//
是否继承基类中所有内容
bool
MutuallyExclusive
//
对应pd中同名参数
Comment Comment
//
关系的注释说明
Namespace Owner
//
关系所属的命名空间
string
Id
//
string
ObjectId
//
string
Name
//
string
Code
//
string
GetConfigValue(
string
name)
//
获取关系中的配置参数
class
Comment
//
注释
string
Text
//
注释的全文本,包含回车换行符
string
[] Lines
//
注释的分行文本,不含回车换行符
class
Domain
//
Domain,对应 SQL SERVER 中的 User Type 类型
string
Id
string
ObjectId
string
Name
string
Code
DataTypeInfo DataType
int
Length
//
数据类型的长度
string
LowValue
//
取值定义的下限
string
HighValue
//
取值定义的上限
string
DefaultValue
//
默认值
ValuePair[] ValueList
//
合法值列表,类似于 enum
Comment Comment
//
注释
string
GetConfigValue(
string
name)
//
获取配置值
class
ValuePair
//
Domain 中合法值的信息,类似于enum
string
Value
//
值
string
Caption
//
值的名字
class
DataTypeInfo
string
Type
//
把DataType中的类似 VA50 中的长度之前的类型,比如 VA
int
Length
//
数据类型的长度
class
Helper
string
Char(
int
ascii)
//
把 ascii 字符变换为对应的字符
int
Ascii(
string
ch)
//
获取字符的ascii码
string
UpCase(
string
text)
//
大写字符串
string
LowerCase(
string
text)
//
小写字符串
string
Trim(
string
text)
//
消除字符串前后空白字符
bool
IsBlankString(
string
text)
//
判断是否空白字符串
string
[] Split(
string
text,
string
splitters)
//
切割字符串,splitters中所有字符作为切割标记
目前经过改进,已经可以支持xml格式的脚本,定义请参考代码中的xsd文件,也支持visual studio 2003工程文件属性中的custom tool,只要运行一下regist.bat,就支持名字为PDMGenerator的自定义工具在编译时进行文件的转换工作。
工程代码请到http://files.cnblogs.com/BigTall/pd-map.zip 。
在使用中会出现 NVelocity 的bug:
1。模版文件中的中文不能输出
2。在 #set($var = "this is 'my \"$baby\"' lover!") 对于连续的引号中的引号处理不正确。
-----------------
2005-5-16 更新
1。给所有的Entity,DataItem,Domain,Attribute,Relationship都加上配置功能
2。修正DataType的类型从string到DataTypeInfo
3。增加RelationshipEntity的实现
4。修正UniqueCode的实现算法
2005-5-31 更新
1。加入inheritance的支持
2。加入支持新的xml格式的脚本文件,以及支持代码库文件
3。支持Visual Studio 2003的custom tool功能,使用PDMGenerate的名字就可以支持编译时转换
4。增加$Helper输出符号,支持简单字符串处理功能,同时规避NVelocity已知错误