电脑桌面
添加蚂蚁七词文库到电脑桌面
安装后可以在桌面快捷访问

NC5客开培训资料-NCV5.5-元数据开发红皮书.docVIP免费

NC5客开培训资料-NCV5.5-元数据开发红皮书.doc_第1页
1/25
NC5客开培训资料-NCV5.5-元数据开发红皮书.doc_第2页
2/25
元数据开发手册具体元数据分析文档请参考-史周军使用元数据编程重要注意事项:不要将元数据的对象在前后台之间传递,这将导致严重的效率问题.明确的说就是不要将元数据对象,比如模块,组件,实体,属性,各种类型等作为远程调用服务的方法参数或者返回值,也不要在自己的数据对象里组合元数据对象,如果的确需要引用元数据对象,请务必设置为transient类型。比如以下为错误做法:对于IService:有方法:IComponentoperation(IBeanbean,Type…);1.元数据总体代码框架图1元数据代码结构图1.1.元数据模型接口定义1.1.1业务模型主要接口及相关概念图2接口关系图对于元数据的业务模型,开发人员首先需要了解的关键概念包括:模块,组件,实体,值对象,业务接口,属性,业务操作,方法,参数,元素,容器,IBean等。模块(IModule)对应目前我们部署环境里modules下的各个目录,比如uap,uapbd,uapeai等,只是部署环境里的module是平级的,而元数据里模块是一个属性结构,也就是说模块可以有子模块,比如uap的子模块有uapbd,uapeai,uapportal,uapqe等。对应数据库表md_module模块是安装的基本单元,元数据所有产生的脚本是以模块为单位导出初始化脚本的。组件(IComponent)描述的是一个相对独立和完整的业务块,主要是从业务层次上进行划分,比如“销售订单”可以作为一个组件,“客商档案”也可以作为一个组件,划分组件时,注意组件间的重用,且注意不要形成相互依赖。组件属于模块,一个模块可以包含多个组件。对应数据库表md_component组件是部署的基本单元,一个典型的组件会包含若干个有相互关系的实体(但只能有一个主实体),组件内还包括服务和操作,服务可以直接生成usm配置文件,操作可以直接生成upm配置文件,另外组件里还可以有业务接口,枚举类型等。实体(IBusinessEntity)是指可以通过一系列连续性(continuity)和标识(identityID)来定义的业务对象,NC原有的大部分VO基本上都算得上是实体。实体属于特定的组件,一个组件可以包含多个实体,组件可以没有任何实体,(比如只有业务接口),但如果有实体,则必须设置一个主实体。对应数据库表md_class值对象(IPropertyType):如果一个对象代表了领域的某种描述性特征,且没有概念性的标识,比如颜色,地址,但也不能一概而论,有些需要取决于具体的业务场景。值对象同样定义在组件里,一个组件可以包含多个值对象。对应数据库表md_class值对象与实体的另一个差别:值对象可以通过判断其所有的属性是否相等来判断值对象是否相等,而两个实体即使所有属性都相等,但主键不相等,也不能说两个实体相等。从这个意义上可以说,值对象是无生命的,而实体是有生命的。自定义实体(ICustomEntity):表达拥有特定属性的一类实体,对应NC里的自定义档案,自定义实体是一种特殊的实体。对应数据库表md_class属性(IAttribute):对应实体里的每个字段,对应数据库表md_property业务操作(IBusinessOperation):表达一个完整的外部服务或者内部服务(service)。业务操作也定义在组件里。对应数据库表md_busiOperation。业务接口(IBizInterface):供实体或者值对象实现的接口,接口本身定义了特定的访问方法。对应数据库表md_class备注:在设计器上,业务接口只能增加属性,相应会生成get方法,比如增加一个name属性,会生成一个getName()方法,方法的返回值可以自由选择。实际上,如果希望灵活运用业务接口,你可以摆脱设计器的限制,你在设计器上设计出一个业务接口,生成代码后,可以给业务接口增加任何方法,当然实现类也由你自己实现,此时只是通过元数据来管理你的业务接口而已。我们可以通过下面的方法Mapnc.md.model.IBusinessEntity.getBizInterfaceMapInfo(StringfullIntefaceClassName)查询实现了特定业务接口的实体中的属性和接口方法的对应关系,如下图所示,如果客户实现了ICodeName<<编码名称接口>>,则customerBean.getBizInterfaceMapInfo(“nc.vo.bd.ICodeName”)将返回<”code”,CodeAttr>,<”name”,NameAttr>,<”displayName”,displayNameAttr>而以下代码则演示了如何在对象级使用业务接口:方法(IOperation):具体的操作方法,和JAVA类的方法同义,可以定义在实体里,也可以定义在业务操作里。对应数据库表md_operation参数(IParameter):方法里的参数,和JAVA类方法里的参数同义。对应数据库表md_parameter元素(IModelElement):模型元素的基本接口,描述了元素的基本信息。容器(IContainer):描述那些可以包含其他元素的元素IBean:实体,值对象,业务接口的共同基本接口。大部分情况下一般对元数据的访问是通过IBean来进行的。Customercust=newCustomer();cust.setPrimaryKey("pkaaaaaaaaaaa");cust.setCode("code001");cust.setName("nameadfafdafasd");NCObjectcustbasObj=NCObject.newInstance(cust);ICodeNamecodename=(ICodeName)custbasObj.getBizInterface("nc.vo.bd.customer.ICodeName");System.out.println(codename.getCode());System.out.println(codename.getName());1.1.2元数据里的数据类型表达1.1.2.1数据类型体系介绍图3元数据里的类型表达元数据的所有数据类型都实现接口IType,IType分为两大类,基本类型(IPrimitiveType)和复杂类型(IComplexType)。基本类型包括String,Double,UFDouble,UFID,UFMoney,BLOB,CLOB,IMAGE等,完整的列表可以查看IType里的static定义,相应的md_class表里会初始化所有的基本类型,md_class表里所有classType<200的均为基本类型。复杂类型主要有四类,从图3可以看到:枚举类型(IEnumType):目前支持String,int类型值的枚举,支持多语言描述。引用类型(IRefType):表示引用另一个Bean,但是本身字段为String类型,记录的是所引用Bean的主键。NC里默认实体间的1-1关联及聚合均采用此种方式集合类型(ICollectionType):表示1-n的关联或者聚合关系,集合实现方法(样式)目前支持数组及List,集合里装的是什么由ElementType表示,ElementType是一个IType,可以为基本类型或者复杂类型。Bean类型(IBean):表示1-1的关联关系或者聚合关系,字段的类型为Bean,即实体或者值对象(业务接口一般不会在类型定义里使用)。复杂类型是模型里的表达方式,在设计器里,复杂类型里的引用类型和集合类型是通过类型样式+数据类型组合而来的。一个属性,除了有类型,还需要类型样式来进一步描述类型的最终形态,比如同样是String类型,有些属性是String数组,而有些是String,另外一些是List,描述数组,列表,还是单一信息的就是类型样式。目前的元数据里有如下集中样式:1)STYLE_SINGLE单一样式,最终的类型就是原始数据类型。2)STYLE_REF引用样式,只用于实体,值对象,设置为引用样式,便可以得到引用类型。3)STYLE_ARRAY数组样式,最终的类型为数组集合类型。4)STYLE_LIST列表样式,最终的类型为List<数据类型>集合类型。5)STYLE_VECTOR不推荐使用,除非兼容老代码6)STYLE_SET暂时不支持。关于简单类型(SimpleType):为了编程方便,比如在数据绑定或者取值赋值时,类型的区分无需太细,我们把基本类型,枚举类型,应用类型统称为简单类型,通过booleannc.md.util.MDUtil.isSimpleType(ITypetype)方法判断即可。具体类型的判断,可以通过nc.md.util.MDUtil工具类提供的is**Type方法进行判定,典型代码如下:Listattrs=bean.getAttributes();for(IAttributeattribute:attrs){ITypetype=attribute.getDataType();if(MDUtil.isPrimitiveType(type)){}elseif(MDUtil.isMDBean(type)){}elseif(MDUtil.isRefType(type)){}elseif(MDUtil.isCollectionType(type)){ICollectionTypecollectionType=(ICollectionType)type;if(MDUtil.isMDBean(elementType)){}elseif(MDUtil.isEnumType(elementType)){}elseif(MDUtil.isPrimitiveType(elementType)){}}elseif(MDUtil.isEnumType(type)){}}1.1.2.2设计器中的数据类型设置请仔细观察上图中各字段的类型设置:1)主键一定要选择为UFID类型,类型样式为single,类型样式是进一步描述类型信息的,single表示单一类型。2)订货人是人员类型,但设置了REF样式,最终订货人为引用类型,邮寄地址、账单地址一样。3)明细为1对多关系,增加1对多聚合关系后或者1对多关联关系后,类型样式会自动设置为ARRAY。注意当去掉关系时,请手工修改此样式,以免造成错误。1.1.3元数据里的数据模型的表达图4数据模型接口图需要说明的是ITable即表的定义与表达。表ITable由于和视图IView均包含字段定义,所以共同继承ITableView,但表内还有主键和外键,本版本一个表可以有多个外键,但只有一个主键,不支持组合主键,V55版暂时不支持中间表和扩展表。如果想了解扩展表或者中间表的机制,可以参考以前的文档。另外图4中IForeignKey上的关系比较复杂,主要因为ITable里有外键,而外键里包含了起始表,结束表,起始字段,结束字段等信息。仔细看一下就不难明白了。设计器里,可以给实体设置对应表的名称,也可以为每个属性定义生成列的名称。设置表名设置字段名称如果是1对多关系或者1对1的聚合关系,对应的字段名称为字表里外键的名称。具体数据模型生成请参考《1.7模型发布及脚本生成》。1.1.4实体间的关系及业务模型到数据模型的ORMAP图5实体间关系表达实体之间目前有4种关系,即Dependency(依赖),Composite(组合)Realized(继承---模型发布、代码生成及持久化暂时没有处理),Relation(关联),关系的定义请查看nc.md.model.AssociationKind枚举类。关系的具体表达由接口nc.md.model.IAssociation进行描述,具体请查看javadoc说明。图5ORMAP信息1.2元数据模型定义实现实现具体请参考代码,根据相应接口,按Ctrl+T可以看继承关系图。1.3元数据查询服务接口nc.md.MDBaseQueryFacade提供元数据基本的一些查询,如查询模块、组件、实体、值对象、属性等,前后台均可调用。支持前台缓存功能,有效减少远程调用。前台缓存能很好的解决元数据加载的效率问题,但是如果开发人员在开发环境经常频繁的修改元数据,则会要求必须重启JStarter才能使得修改生效,为避免此问题,可以在JStarter的启动参数里增加参数,在开发时临时关闭前台缓存功能。-Dnc.md.detectEachTime=truenc.md.MDQueryService后台查询,前台请不要调用,前台全部使用MDBaseQueryFacade,否则会导致严重后果,后果自负,如果MDBaseQueryFacade的查询方法不全,可以通知cch添加,MDQueryService服务为元数据自身查询服务的统一入口,通过此入口类可以请求不同的查询服务,在后台,如果是一些简单查询,比如通过名称,则优先使用nc.md.MDBaseQueryFacade提供的查询方法通过此查询服务可以分别得到四种查询服务接口:1)针对外部应用的查询服务,主要根据名称查询-IMetaDataQueryService2)针对内部应用的查询服务,主要根据ID查询-IMetaDataInnerQueryService3)针对数据模型的查询服务-IDataModelQueryService4)针对元数据管理工具的查询服务(没有缓存,实时更新)-IManagerQueryService1.4基于元数据的数据访问接口图6数据访问接口回忆没有元数据的年代,我们如何访问数据呢?列举一二:当需要从模板(单据模板,打印模板,报表模板,会计平台)上获取相关数据时,一般通过getColValue(a,b,c,d)公式,其中的a,b,c,d不是业务字段,而是数据库表名,列名,这就要求开发人员、实施人员对基本档案,业务表有非常清楚的了解这个要求对实施人员就比较苛刻了,所以负责具体业务的开发人员经常能接到远在客户现场的实施打来电话“你好,能告诉我某表某字段什么含义吗?能告诉我如何取数吗?”,晕。。。关键是,一个getColValue解决不了问题,所以在我们的公式定义中,经常会看到很多getColValue,8行10行20行,最终就是为了得到几个需要的业务值!!而这还不能满足需要,所以公式中出现了getColValue2,getColValueMore,getColValueWithCond…等更多更复杂的函数。程序员编写程序时也同样面临此类困惑,经常为了查询某个数,不惜在代码里调用公式进行查询,或者通过一些通用的查询服务,比如IUAPQueryBS,或者自己编写Service,DAO来实现查询字段,非常的影响开发效率。相信大多开发人员都有过此种经历。说了这么多,就是要体现元数据的好处,基于元数据,终于可以摆脱配置复杂公式,编写DAO,或调用一些本不适合的方法了!元数据取数的优势:1)模板上不再需要定义公式,直接从模型树上拖拉需要显示的业务字段即可。2)取数完全基于模型角度,完全不用了解数据库结构。3)支持复杂条件查询,支持批量取数,有效提高数据访问效率。基于元数据的数据访问主要用到DASFacade及NCObject类。类DASFacade是一个helper性质的工具类,封装了常见的数据访问,元数据对象创建等方法,部分方法和NCObject效果类似,但是DASFacade的好处是在没有NCObject对象实例的情况下也可以使用,另外DASFacade基于路径取数的方法支持绝对路径和相对路径,而NCObject只支持相对路径。当使用以下功能,建议使用DASFacade1)如下场景的取数和设数:路径和所给出的NCObject实例并不是一个分支,或者说路径对应的属性不是NCObject实例的直接属性,如下图所示,给出的ncobject为a对应的实例,但访问路径为b.e.f2)需要从map数据构造NCObject实例,或者从NCObject实例得到map数据。3)需要根据关键属性或者关键属性数组查询相应的值,比如根据客商ID得到客商的名称、编码等。4)自定义复杂查询条件,查询模型各个层次的值,类似OQL,比如:Rootacdbef对于上述模型,我们可以尝试取得如下的值:订货人.编码=0002,邮寄地址.邮政编码=100090的所有订单的账单地址.详细地址。程序里可以这样实现:当使用以下功能,建议使用NCObject:1)平台性质的模块,不关心具体的VO类型,如果是业务实现代码,不建议使用NCObejct,除非特别的取数需要。2)希望将实例绑定元数据,以弱类型进行访问。更多基于数据访问的细节,请参考以上两个类的javadoc。//得到订单的元数据IBeanbean=MDBaseQueryFacade.getInstance().getBeanByFullClassName("订单类名");//创建查询sessionQuerySessionsession=QuerySessionFactory.createQuerySession(bean);//增加条件session.addCondition(Restrictions.and(Restrictions.eq("订货人.编码","0002"),Restrictions.eq("邮寄地址.邮政编码","100090")));//增加待查询字段session.addPath(newString[]{"账单地址.详细地址","账单地址.邮编"});//返回行结果集Collectionres=DASFacade.queryPrimaryKeyByCriteriaReturnRowSet(session);返回的结果为Collection,内部为hashmap,每一个hashmap代表一行记录,可以通过:map.get("账单地址.详细地址")取得"账单地址.详细地址"1.5元数据中的访问器图7元数据中的访问器访问器主要用于解决JAVA类与模型不一致的情况,通过访问器使得用户可以按照标准模型来访问实际上不符合模型结构的java类和对象实例。访问器的常见设置:1)如果是主子表,多字表结果,并且希望生成和NC产品兼容的代码,一律设置访问器为聚合AGGVO,同时选代码样式为传统样式,如图所示:点击设计器空白区域,在组件的属性里设置代码风格在主实体的属性框里设置访问器类型,同时可以修改聚合VO的名称此时不要忘记设置字表对应属性的访问策略为BodyOfAggVOAccessor2)如果希望生成标准的OO代码,可以设置代码风格为标准样式,访问器选择NCVO即可,不过后续的模板及各种框架的支持需要考虑。1.6基于元数据的持久化1.6.1元数据自身的缓存和持久化图8元数据自身持久化类图1.6.2基于元数据的持久化框架实现图9基于元数据的持久化类图nc.md.persist.framework.IMDPersistenceService持久化服务接口,主要为更新、保存及删除,CMT,容器管理事务nc.md.persist.framework.IMDPersistenceQueryService查询服务接口,不带事务。1.7模型发布及脚本生成1.7.1简单VO简单VO内部全部为简单字段,与其它实体无任何关系,该实体除了客户类型为枚举类型,其它字段均为基本类型,和其它实体没有任何关系。这是最简单的一种类型,依照实体默认产生数据库表,表名可以在设计器上指定,字段和实体属性保持一致即可,字段名也可以在设计器上设置。同时在md_ormap表里保存ORMAP信息。[ORMAP信息]实体属性表列名BECUST001customerIDBd_customercustomerID1.7.2一对一引用关联一个实体一对一关联了另一个实体,且在产生的JAVA类里关联源字段为字符串类型,而不是被关联实体的类型,我们把这种关联称之为引用关联,称关联源字段的数据类型为引用类型。比如客户关联了地区,客户里有一个字段叫[客户所在地区],称为关联源字段,如果是引用关联,则产生的客户JAVA类里,关联源字段为String类型,记录的是地区的主键ID,反之如果是非引用关联,则生成的字段为地区类型,称为嵌套关联。生成的ORMAP信息和简单实体是一样的。[ORMAP信息]实体属性表列名BECUST001customerIDBd_customercustomerIDBECUST001Pk_areaBd_customerPk_area同时产生一条foreignKey信息:[ForeignKey信息]关联表外键被关联表主键Bd_customerPk_areaBd_areaPk_area1.7.3一对一关联对于正常的1对1关联,生成的ORMAP信息及外键信息同上面的引用关联只是生成代码时,在主实体中相应的字段类型为关联实体类型,而不是PK值。[ORMAP信息]实体属性表列名BECUST001customerIDBd_customercustomerIDBECUST001areavoBd_areaPk_area[ForeignKey信息]关联表外键被关联表主键Bd_customerPk_areaBd_areaPk_area1.7.4一对一组合1对1组合关系,可以看作时1-n组合关系的特例,为了避免持久化时的特殊处理,无论是生成的数据库表,字段,还是ORMAP信息,Foreignkey信息都和1-n组合完全相同。【注意与通用框架有一些差异】生成表时,在子实体对应的表上增加一外键列,引用的是主实体对应表的主键。注意:如果此时子实体刚好又关联了主实体,那么就不需要增加此外键列了代码里可以看到此逻辑。[ORMAP信息]实体属性表列名BECUST001customerIDBd_customercustomerIDBECUST001areavoBd_customerPk_area保存时,只保存主实体,此时areavo的主键应该为已知,直接拿到areavo的主键,和客商信息一起保存到bd_customer表中。[ForeignKey信息]关联表外键被关联表主键Bd_customerPk_areaBd_areaPk_area1.7.5一对多组合对于一对多组合,保存时除了保存主实体,还要保存被组合的子实体,删除时也一起删除,查询时提供全部查询和只查主实体对象而后懒加载子对象两种方式(考虑直接在主实体里直接生成懒加载的代码-----getChilds()的方法)。[ORMAP信息]实体属性表列名OrderItemitemspo_orderItemDetailFk_orderItem_IDOrderItemcustomerspo_orderItem_EXfk_customerOrderItemoperatorspo_orderItem_EXfk_operator其中items关联的是组件内实体,订单项条款,相应的生成数据库表po_orderItemDetail,该表中增加一外键列,存贮po_orderItem的主键。保存时和hibernate的一对多有所不同,不是先插入子表,后更新子表,而是先保存主表,取得主表主键,然后直接保存子表。Customers关联的是组件外实体,对于组件外实体,由于不能直接修改其对应的表,所以需要在本组件内重新生成一张子表,存储一对多关系。注意如果关联多个组件,也只创建一张表,具体形式如下:po_orderItem_EXFk_orderItem_ID(订单项ID)fk_customer(客商)fk_operator(操作员)ID1custIDAID1custIDBID1EmployAID1EmployBID1EmployCID1EmployD[ForeignKey信息]关联表外键被关联表主键po_orderItemDetailFk_orderItem_IDpo_orderItemPk_orderItem_IDpo_orderItem_EXfk_operatorbd_operatorpk_operatorpo_orderItem_EXfk_customerbd_customerpk_customerpo_orderItem_EXFk_orderItem_IDpo_orderItemPk_orderItem_ID保存订单项时,逐个的对每个字段进行处理,每个字段都到ORMAP里取相应的ORMAP信息,对于简单类型,ORMAP就是fieldName-ColomnName;而对于1-n的复杂类型,ORMAP信息需要得到映射的表和字段,相应将n数据保存到映射表中,且保存之前将本实体的主键关联到n数据,一起参与生成INSERT语句。查询订单项时,比如查询客商时:利用BaseDAO.retrieveByClause()方法,对下面方法得到的客商PK,做in条件查询。Selectfk_customer(客商)frompo_orderItem_EX(ORMAP)whereFk_orderItem_ID=‘ID1’andisNull(fk_customer,0)=0其中Fk_orderItem_ID为外键,对应的是po_orderItem的主键。不过如果客商下面还有复杂字段,那么BaseDAO.retrieveByClause()方法也需要重写。注意:目前不支持组合主键,只单一主键,但可以设唯一键,组合主键带来的问题:1)pubOID生成机制2)表关联时,必然要求组合外键3)NC不支持1.7.6一对多关联ORMAP及外键表和一对多组合一样,只是保存时不保存关联对象。查询处理相同。不过有一种情况,1对多组合不存在,但1对多关联却会存在:如果是同一组件内,多个实体1-n关联了同一个实体,比如订单,发票都引用了合同,那么在合同表里增加订单与发票ID列。合同ID订单ID发票IDID1D001F001ID2D001F0031.7.7多对多关联多对多在业务模型里表现为两个1-n关联关系,多对多关系要求一定在同一个组件内,否则组件间就会有相互依赖,比如对象模型如下:订单发票合同数据库如下:需要生成中间表,中间表取两个实体的主键。Tb_Book_author_mid书ID作者ID发行商IDB1A1A1B2A1A1B3A1A1B2A2A2[ORMAP信息]实体属性表列名BookauthorsTb_Book_authorautherIDAuthorbooksTb_Book_authorbookID保存书对象时,首先保存到tb_book表,对于作者字段,取得所有作者,将书和作者的对应关系保存到中间表。查询时,支持懒加载方式,如果查书对象,则只查书对象,作者字段为空,只有在请求访问作者字段时,再进行查询。(根据BOOKID,到中间表查询所有作者ID,然后到作者表查询作者,一个关联查询)1.7.8自关联(自聚合)实体自己关联自己,或者自己聚合自己,自己关联自己同样也分1-1关联,1-n关联,1-1聚合,1-n聚合等,比如下图中的组织:书ID书名书编号出版社作者ID作者名出生年月简介1-n自关联,1-1聚合,1-n自聚合,需要生成扩展表org_ex,记录组织和组织的对应关系。ORMAP及外键信息同1-n模块外关联。1.8代码生成代码生成的规则:1)查看主实体上的关系,如果主实体上存在1个1-n聚合关系,则生成AggregatedValueObject类型的包装类,主实体对应生成主表VO,聚合的子实体生成子表VO;如果主实体上存在多个1-n聚合关系,则生成多子表类型IExAggVO。2)除了主实体,其他实体上的关系一律按照面向对象生成,及直接关联或者聚合在实体对应的VO内部。2.基于元数据的平台应用单据模板,查询模板,打印模板,数据交换,流程平台,外部交换平台,权限。。。

1、当您付费下载文档后,您只拥有了使用权限,并不意味着购买了版权,文档只能用于自身使用,不得用于其他商业用途(如 [转卖]进行直接盈利或[编辑后售卖]进行间接盈利)。
2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。
3、如文档内容存在违规,或者侵犯商业秘密、侵犯著作权等,请点击“违规举报”。

碎片内容

NC5客开培训资料-NCV5.5-元数据开发红皮书.doc

您可能关注的文档

确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息
QQ群
  • 答案:my7c点击这里加入QQ群
支持邮箱
微信
  • 微信