使用 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 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的自定义工具在编译时进行文件的转换工作。

工程代码请到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已知错误
   

posted on 2005-04-28 15:07  老翅寒暑  阅读(8006)  评论(6编辑  收藏  举报

导航