使用 NVelocity 解析 PowerDesigner 的cdm文件
使用 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 line2
comment line n
[config]
name1=value1 // 注释
nameN=valueN // 注释 N
从 $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的自定义工具在编译时进行文件的转换工作。
工程代码请到https://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已知错误
公众号:老翅寒暑