在 IBM InfoSphere Master Information Hub 中引入实体子类型

编写实体子类型和支持服务

在本教程中,学习如何为 IBM® InfoSphere™ Master Data Management Server 和 InfoSphere Master Information Hub 实现实体子类型和支持服务。通过使用实体子类型,可以在框架中引入新的实体,它们可以由父实体的服务处理。这有助于为使用 Master Information Hub 创建的新领域实现服务互操作性和可扩展性。

Stephanie J. Hazlewood, 软件架构师, IBM

Stephanie Hazlewood 是多伦多实验室 IBM Master Data Management Server 团队的架构师,她领导 MDM 的 Advanced Technology(AdTech)团队。从 8 年前 MDM Server 产品初次发布到现在,她为 MDM Server 产品的核心设计和开发做出了杰出的贡献。除了 Master Data Management 架构和解决方案外,她的专长还包括 Knowledge Management(KM)软件和实践,以及虚拟学习社区。Stephanie 曾为 DWL 和多伦多大学 Center for Applied Cognitive Science(现在的 Institute for Knowledge Innovation and Technology)工作,并拥有 University of Western Ontario 的硕士学位。



Lin Qiao, 软件架构师, IBM

Lin Qiao 的照片Lin Qiao 是多伦多实验室 InfoSphere Master Data Management Server 团队的架构师,已经在产品团队工作了 7 年多。她设计了许多关键的 MDM Server 特性并负责它们的开发,以前为 DWL 工作过。



2010 年 4 月 16 日

开始之前

在使用 InfoSphere Master Information Hub 或 InfoSphere Master Data Management Server 为解决方案定义新实体时,可能需要服务能够处理具有超类型-子类型关系的实体。如果实体没有共同的属性,它们就是不同类型的。一些实体具有某些共同的属性,比如标识符(主键),而其他属性不同,这些实体可能具有共同的超类型。尽管这些实体共享一些属性,但是它们不是相同的。例如,人和植物都有定义生物所需的属性(一般化),但是还有一些并不共享的属性,它们对一般化定义进行进一步特殊化,需要以不同的方式处理。在 MDM 或 Master Information Hub 解决方案中,业务可能要求涉及超类型-子类型关系的实体参与同一组服务,但是要求服务以不同的方式处理它们。本教程讲解如何实现新的类型层次结构并定义相关的服务,从而支持这种特殊化处理。

目标

  • 了解什么时候应该使用子类型,什么时候应该使用数据扩展。
  • 了解如何创建实体超类型、子类型和相关服务。
  • 了解 Master Information Hub 实体和服务的结构,以及如何定制子类型实体及其服务的实现。
  • 了解创建子类型实体和使用它们的三种服务(添加、更新和按标识符查询)的步骤,同时考虑性能因素。
  • 了解为 Master Information Hub 解决方案中现有的类型层次结构和相应服务创建扩展子类型的步骤。

前提条件

本教程是为 IT 架构师和 IT 专家编写的,帮助他们进一步了解如何为 InfoSphere Master Information Hub 设计和开发服务。本教程假设您有使用 InfoSphere Master Information Hub/MDM Server Workbench 开发解决方案的经验。具体地说,假设您:

  • 能够使用 Development Environment Setup Tool (DEST) 配置和使用开发环境。
  • 熟悉使用 InfoSphere Master Information Hub/MDM Server Workbench 创建、定制和部署新的实体和实体扩展的方法。

系统需求

要想学习本教程,您的系统应该满足以下需求:

  • 2GB 或更多的内存
  • 15GB 空闲磁盘空间
  • 系统使用 Windows 操作系统,可以安装 IBM Rational® Software Architect, Version 7.5.4 for IBM WebSphere® Software(或更新的版本)和 Master Information Hub Workbench

本教程是针对 InfoSphere Master Information Hub 和 InfoSphere Master Data Management Server 的 9.0 版开发的。


概述

许多组织都有不受管理的主数据,这些数据可能是企业并购的结果,也可能是由于业务部门没有共享应该共享的信息存储库造成的。不受管理的主数据会导致数据不一致和不准确。可以使用 IBM InfoSphere Master Information Hub 创建基于服务的 Java™ EE 应用程序,从而为业务系统应该共享的信息提供整合的视图和发布点。

Whereas InfoSphere Master Data Server 为 Party、Product 和 Account 领域提供开箱即用的操作功能。Master Information Hub 提供构建块、运行时平台和工具集,可以用它创建定制的领域,从而处理非传统的主数据用例(例如引用数据)。在操作风格的主数据管理中,用 Master Information Hub 构建的应用程序作为联机事务处理 (OLTP) 系统响应多个服务消费者的请求。这些无状态的服务(无论是平台直接提供的,还是使用 Master Information Hub Workbench 创建的)使用一个健壮的应用程序框架,这个框架提供审计、检验和在面向服务架构 (SOA) 中的可见性规则等关键特性。

图 1. InfoSphere Master Information Hub 和 MDM Server(领域)
图中包含 InfoSphere Master Information Hub 存储库、运行时平台和领域(MDM Server 领域和在 Master Information Hub 平台上构建的定制领域)。这个图说明 Master Information Hub Workbench 生成服务和结构的功能,可以定制现有的领域和创建新的领域

可以使用 InfoSphere Master Information Hub Workbench 创建和扩展实体、服务和用户界面,帮助数据专员管理信息。它提供为 InfoSphere Master Information Hub 开发组件所需的建模、代码生成、开发和测试环境。Master Information Hub Workbench 与 IBM Rational Software Architect 集成,因此可以访问这个产品提供的标准软件开发功能,包括源代码控制和 Java EE 部署和测试环境与 WebSphere Application Server 的集成。

定制领域的构建块称为附加项(addition)。这些附加项包括在 Master Information Hub 平台上处理信息所需的接口、实体、服务和支持元数据/数据库结构。可以使用 Master Information Hub Workbench 创建新的附加项,本教程讲解如何利用这些资产为新领域构建和使用实体子类型框架。


实体子类型特性

Master Information Hub 和 MDM Server 的 9.0 版引入了实体子类型特性。

这个特性扩展了运行时平台的功能,它支持:

  • 多级实体子类型,对于类型的子类型数量没有限制。(注意:本教程建议采用一对一的数据库表到子类型映射,因此随着层次结构深度的增加,性能会降低。在设计子类型层次结构时应该记住这一点。)
  • 对象多态性 — 可以定义惟一的业务键、检验和可见性规则 (RoV)。
  • 父服务处理子类型,预期的服务行为与执行此类型的细粒度服务的结果相同。
  • 使用扩展框架(行为扩展、数据扩展)扩展子类型。(注意:数据扩展和子类型扩展只限于叶节点;见 图 2 中的 “Male”。)
  • 为每个类型和它或它的父类型包含的任何子对象定义持久化和查询战略。

实体子类型特性不允许:

  • 子类型有多个超类型(不允许多重继承)
  • 为 MDM Server 或 Master Information Hub 中现有的实体创建子类型

Master Information Hub 和 MDM Server 的运行时平台使用元数据发现服务调用,并把服务调用转发到适当的子类型服务(如果有的话)。请考虑 图 2 中的类型层次结构和相应的服务。如果调用 addParty(Pet),服务的表现会与直接调用 addPet(Pet) 相同。

图 2. 子类型层次结构和服务表现
说明类型的层次结构:Party (SParty) 作为根父类型;LivingThing 是 Party 的子类型;Human 和 Pet 是 LivingThing 的子类型;Male 是 Human 的子类型。Male 以另一种颜色显示,表示它是预先编写的类型层次结构的扩展子类型

表 1 提供一些示例服务。这个表说明,如果把子类型传递给超类型的方法,服务的表现会与直接调用子类型的方法一样。

表 1. 示例服务
调用父服务表现与以下服务调用相同
addSParty(LivingThing)addLivingThing(LivingThing)
updateSParty(Human)updateHuman(Human)
getHuman(MaleID, DWLControl)getMale(MaleID, DWLControl)
addSParty(Male)addMale(Male)

注意:本教程中描述的实体不是现有的 MDM 实体。使用 Party 实体只是为了说明概念,并不代表 InfoSphere Master Data Management Server 9.0 中的 Party 实体或它的服务。不支持使用本教程讨论的模式为现有的领域实体创建子类型。

对于本教程中构建的示例,图 3 说明在控制器上调用 addParty 服务的情况。这个调用传递一个 PetBObj,这会导致在 executeTx() 方法中截取服务流。handleSubtypes 方法使用元数据把这个服务调用转发给适合处理这个类型的方法(在这里,是 handleAddPet)。因为转发在调用 preExecute() 之前发生,所以会根据传递给系统的子类型执行所有控制器级 preExecute 功能。

图 3. 在传递子类型时父服务的执行过程
这个序列图显示在处理子类型实体时发生的方法调用转发

什么时候应该使用实体子类型而不是数据扩展

尽管子类型和数据扩展都使用 Java 继承作为基础机制,但是 Master Information Hub 平台解释它们的方式有一个关键差异。在对现有的 Master Information Hub 实体进行扩展并添加字段时,并不需要通过引入新服务提供新实体特有的处理(例如检验和业务逻辑)。通过调用扩展框架(例如 addRecordupdateRecordgetRecorddeleteRecord API 调用),由为实体预定义的所有服务处理这些数据扩展。对于实体子类型,添加新字段会为实体提供新的业务含义。因此,需要新服务,实体的处理独立于它的父类型的处理。例如,实体超类型有自己特有的业务逻辑、检验、业务键、可见性规则和审计历史。应该注意,到 9.0 版为止,还不能通过修改数据模型中现有的实体来利用实体子类型框架。

表 2. 实体子类型和数据扩展的对比
子类型数据扩展
不归类为扩展在请求/响应中总是归类为扩展 (TCRMExtension/DWLExtension)
需要提供新的细粒度服务,从而处理此类型特有的表现或业务逻辑不需要添加新的服务,它们只是参与现有的开箱即用服务
定义新的业务键;定义业务对象的惟一性应该使用与被扩展的对象相同的业务键配置

在 InfoSphere Master Information Hub 中创建使用实体子类型的应用程序

创建示例应用程序

在本节中,我们要创建一组 MDM 实体,它们组成一个类型层次结构,还要创建与每个实体相关联的服务。可以使用 InfoSphere Master Information Hub 或 Master Data Management Server, Version 9 Workbench 创建这些实体并生成部署它们所需的资源。在此之后,定制生成的资源,让服务利用实体子类型框架。图 4 说明这个类型层次结构中的实体及其关系。

按以下步骤创建示例应用程序并生成资源。如果您不熟悉 InfoSphere Master Information Hub Workbench,请通过 InfoSphere Master Information Hub Workbench Guide 了解如何使用这个工具。

  1. 在 Master Information Hub Workbench 中,创建一个 MDM Module Project。
  2. 在新的模块项目中,为示例类型层次结构中的每个实体创建一个 MDM 实体。

    要想定义实体:

    • 必须为实体的表定义相同的主键。在这个示例中,每个实体都使用 partyId 作为主键。
    • 必须在根类型实体中定义一个 groupName 字段,它的类型为 “String”。它是必需的字段,当只向服务提供标识符(例如 partyId)时,实体子类型框架使用它为查询事务确认记录的真实类型。只能在层次结构的根类型中定义这个字段。

    图 4 和表 3 提供每个示例实体的信息。

    图 4. 数据模型
    为本教程创建的实体的实体-关系图,即数据模型
表 3. 示例 Master Information Hub 实体及其属性
Master Information Hub 实体Master Information Hub 实体属性
SPartypartyId: Long
displayName: String
groupName: String
LivingThingpartyId: Long
age: Short
HumanpartyId: Long
citizenship: String
PetpartyId: Long
kidIndicator: String
  1. 定义了所有实体之后,使用 Workbench 生成源代码和资源。

定制源代码

Master Information Hub Workbench (Version 9.0) 生成的代码和资源不会自动地使用平台的实体子类型框架。必须定制这些资产以启用子类型支持。

  1. 实现业务对象 (BObj) 之间的关系,见图 5:
    图 5.业务对象 (BObj) 类图
    业务对象之间的关系,LivingThingBObj 扩展 SPartyBObj;HumanBObj 扩展 LivingThingBOBj;PetBObj 扩展 LivingThingBObj

    LivingThingBObj 扩展 SPartyBObj;HumanBObj 扩展 LivingThingBOBj;PetBObj 扩展 LivingThingBObj。

  2. 接下来,定制为层次结构中的每个 BObj 生成的代码。
    1. 对于根类型 BObj,删除把 groupName 放进 metaDataMap 的代码。例如,在 SPartyBObj 的 init() 中,删除以下代码行:
           metaDataMap.put("GroupName", null);
    2. 另外,从 SPartyBObj 的 refreshMap() 删除以下代码行:
           metaDataMap.put("GroupName", getGroupName());
    3. 对于每个子类型 BObj,删除 LastUpdateTxIdLastUpdateUser 属性的获取器/设置器代码,因为在根实体类型中已经存在这些属性了。例如,在 LivingThingBObj 中:
      • 删除 LivingThingLastUpdateTxId 的获取器/设置器方法。
      • 删除 LivingThingLastUpdateUser 的获取器/设置器方法。
      • 与根实体中的 GroupName 一样,从 metaDataMap 中删除 LivingThingLastUpdateTxIdLivingThingLastUpdateUser
  3. 定制组件类和它们的关系。层次结构中的每个实体类型使用一个业务组件。图 6 说明本教程需要实现的业务组件和关系。例如,LivingThingComponent 扩展 SPartyComponent。
    图 6. 组件类图
    这个图说明本教程要实现的控制器组件、业务组件和接口。SPartyTxnBean 类是事务控制器组件,它实现 SPartyTxn 接口。层次结构中各个类型(SParty、LivingThing、Human 和 Pet)的所有添加和更新事务都在这个接口中定义。SPartyFinderImpl 类是发现器控制器组件,它实现 SPartyFinder 接口。层次结构中各个类型的所有查询服务都在这个接口中定义。SPartyComponent 是一个业务组件,它实现 SParty 接口并扩展 TCRMComponent。LivingThingComponent 实现 LivingThing 接口并扩展 SPartyComponent。HumanComponent 和 PetComponent 都是扩展 LivingThingComponent 的业务组件,但是它们分别实现 Human 和 Pet 接口。在业务组件的接口之间没有继承关系。例如,LivingThing 接口并不扩展 SParty 接口。SParty 类型的添加、更新和获取服务都在 SParty 接口中定义。LivingThing 类型的添加、更新和获取服务都在 LivingThing 接口中定义
  4. 对于每个实体,通过定制业务组件中的 handleAdd() 方法,使用实体子类型框架执行添加事务。
    • 对于根实体,在持久化对象本身之前,必须填充 groupName。例如,在清单 1 中,粗体的代码显示 SPartyComponent 中的 handleAddSParty()
      清单 1. SPartyComponent 中的 handleAddSParty()
      public DWLResponse handleAddSParty(SPartyBObj theSPartyBObj) throws Exception {
          ......  //prepare status 
      
          // Populate group_name for the root type from metadata v_group table.
          EObjSParty eobjSParty = theSPartyBObj.getEObjSParty();
          IGroupElementService theGroupElementService = GroupElementServiceHelper
                                   .getGroupElementService();
          Group group = theGroupElementService.getGroup(theSPartyBObj.getClass()
                          .getName());
          eobjSParty.setGroupName(group.getGroupName());	
          		
          // Pluggable Key Structure implementation
          ......
          
          Persistence theSPartyBObjPersistence = getBObjPersistenceFactory()
      			.createSPartyBObjPersistence(SPartyBObjQuery.SPARTY_ADD,
      					theSPartyBObj);
          theSPartyBObjPersistence.persistAdd();
      
          ....  //persist child objects if there is any             
          ...... //prepare and return the response 
      }
    • 对于子类型实体,需要先持久化它的超类型,然后根据它的超类型填充主键。例如,清单 2 中的示例代码显示 LivingThingComponent 中的 handleAddLivingThing()
      清单 2. LivingThingComponent 中的 handleAddLivingThing()
      public DWLResponse handleAddLivingThing(LivingThingBObj theLivingThingBObj)
                            throws Exception {
          // 1. persist super type data
          DWLResponse response = handleAddSParty(theLivingThingBObj);
      
          // 2. populate the primary key from super type to sub type EObj
          theLivingThingBObj.getEObjLivingThing().setSPartyId(
      		theLivingThingBObj.getEObjSParty().getSPartyId());
      
          // 3. persist subtype data 
          Persistence theLivingThingBObjPersistence = getBObjPersistenceFactory()
      				.createLivingThingBObjPersistence(
      				LivingThingBObjQuery.LIVING_THING_ADD,
      				theLivingThingBObj);
          theLivingThingBObjPersistence.persistAdd();
      
          return response;
      }
  5. 对于每个子类型实体,通过定制组件中的 handleUpdate() 方法,使用实体子类型框架执行更新事务。

    根实体的更新事务与常规实体相同,不需要修改。对于子类型,需要先更新它的超类型。例如,清单 3 显示 LivingThingComponent 中的 handleUpdateLivingThing()
    清单 3. LivingThingComponent 中的 handleUpdateLivingThing()
    public DWLResponse handleUpdateLivingThing(
    	LivingThingBObj theLivingThingBObj) throws Exception {
    
        //1. Update super type
        DWLResponse response = handleUpdateSParty(theLivingThingBObj);
    
        //2. Update sub type
        if (!theLivingThingBObj.isRedundantUpdate()) {
          Persistence theLivingThingBObjPersistence = getBObjPersistenceFactory()
                .createLivingThingBObjPersistence(
          LivingThingBObjQuery.LIVING_THING_UPDATE,
    		theLivingThingBObj);
          theLivingThingBObjPersistence.persistUpdate();
        }
    
        return response;
    }
  6. 对于每个实体,通过定制组件中的 handleGet() 方法,使用实体子类型框架执行获取事务(按标识符获取)。

    子类型实体中的获取事务并不调用它的超类型实现,因此只向数据库发出一个查询。也就是说,应该使用一个包含所有相关联结的 SQL 从多个表获取数据。
    1. 在根获取事务的查询中,确保返回 GROUPNAME。例如,清单 4 提供在 SPartyInquiryData 中为 getSParty 定义的查询 SQL:
      清单 4. SPartyInquiryData 中为 getSParty 定义的 SQL
      static final String getSPartySql = "SELECT r.SPARTY_ID SPARTY_ID, 
      r.DISPLAY_NAME DISPLAY_NAME, r.GROUP_NAME GROUPNAME,r.LAST_UPDATE_DT 
      LAST_UPDATE_DT, r.LAST_UPDATE_USER LAST_UPDATE_USER,r.LAST_UPDATE_TX_ID 
      LAST_UPDATE_TX_ID FROM SPARTY r WHERE r.SPARTY_ID = ? ";
    2. 修改每个子类型实体的查询,使用 JOIN 获取分布在多个表中的数据。例如,Pet 实体的数据分布在 SParty、LivingThing 和 Pet 表中。修改 PetInquiryData 中为 getPet 定义的查询 SQL,用单一 SQL 获取数据:
      清单 5. PetInquiryData 中为 getPet 定义的 SQL
      Public interface MaleInquiryData{
      
          ......
      
      static final String tableAliasString = "tableAlias (
        PET => mdm.est.samples.entityObject.EObjPet,
        H_PET => mdm.est.samples.entityObject.EObjPet,
        LIVINGTHING => mdm.est.samples.entityObject.EObjLivingThing,
        H_LIVINGTHING => mdm.est.samples.entityObject.EObjLivingThing,
        SPARTY => mdm.est.samples.entityObject.EObjSParty,
        H_SPARTY => mdm.est.samples.entityObject.EObjSParty)";
      
      @Select(sql="SELECT C.SPARTY_ID, C.KID_INDICATOR, C.LAST_UPDATE_DT, 
      C.LAST_UPDATE_USER, C.LAST_UPDATE_TX_ID, B.SPARTY_ID, B.LAST_UPDATE_DT, 
      B.LAST_UPDATE_USER, B.LAST_UPDATE_TX_ID, A.SPARTY_ID, A.DISPLAY_NAME, 
      A.LAST_UPDATE_DT, A.LAST_UPDATE_USER, A.LAST_UPDATE_TX_ID 
      FROM SPARTY A,
      LIVINGTHING B, PET C  WHERE A.SPARTY_ID = B.SPARTY_ID 
      AND B.SPARTY_ID = 
      C.SPARTY_ID AND C.SPARTY_ID = ? ", pattern=tableAliasString)
      Iterator<ResultQueue3<EObjPet,EObjLivingThing,EObjSParty>> 
      	 getPet(Object[] parameters);  
      }
    3. 定制每个子类型的 ResultSetProcessor 中的 createObject() 方法。
      清单 6. PetResultSetProcessor
      public Object createObject(Object eObjs) throws Exception {
          PetBObj theBObj = (PetBObj) super.createBObj(PetBObj.class);
          Queue eobjQueue = (Queue) eObjs;
      
          if( !eobjQueue.isEmpty() ) {
              EObjPet theEObj = (EObjPet)  eobjQueue.remove();
              theBObj.setEObjPet( theEObj );
                  
              EObjLivingThing livingthingEObj 
              = (EObjLivingThing) eobjQueue.remove();
              theBObj.setEObjLivingThing(livingthingEObj);
                  
              EObjSParty spartyEObj = (EObjSParty) eobjQueue.remove();
              theBObj.setEObjSParty(spartyEObj);
          }
          return theBObj;
      }
  7. 定制每个实体的 Web 服务。
    • 实现传输对象类的关系。例如,让 LivingThing 类扩展 SParty。关系见图 7:
      图 7. Web 服务传输对象类图
      这个图说明在为实体生成的传输对象之间必须建立的关系。Human 和 Pet 传输对象类必须扩展 LivingThing 传输对象类。LivingThing 必须扩展 SParty 传输对象类。SParty 传输对象类必须扩展 PersistableObject 类
    • 在子类型传输对象类中删除 SPartyId 的获取器和设置器方法。在这个示例中,它们是 LivingThing、Human 和 Pet 类。
    • 实现响应类的关系。例如,让 LivingThingReponse 类扩展 SPartyResponse。关系见图 8:
      图 8. Web 服务响应对象类图
      这个图说明在为实体生成的响应对象之间必须建立的关系。HumanResponse 和 PetResponse 类必须扩展 LivingThingResponse 类。LivingThingResponse 必须扩展 SPartyResponse 类。SPartyResponse 类必须扩展 ResponseObject 类
    • 实现转换器类的关系。例如,让 LivingThingBObjConverter 类扩展 SPartyBObjConverter。关系见图 9:
      图 9. Web 服务转换器类图
      这个图说明在为实体生成的转换器对象之间必须建立的关系。HumanBObjConverter 和 PetBObjConverter 类必须扩展 LivingThingBObjConverter 类。LivingThingBObjConverter 必须扩展 SPartyBObjConverter 类。SPartyBObjConverter 类必须扩展 SimpleBObjConverter 类

定制 XSD

  1. 在 Remote Method Invocation (RMI) 服务的请求和响应 XML Schema Definition (XSD) 中,定义 BObj 之间的扩展关系(见上面的 图 5),注意以下几点:
    • 在根实体类型定义中,把共有的对象声明(比如 TCRMExtension 和 PrimaryKeyBObj)转移到类型的开头。
    • 在根实体类型定义中,确保删除 GroupName。
    • 在子类型实体定义中,确保删除 LastUdpateUserLastUpdateTxId

    清单 7 给出 SPartyBObj 和 LivingThingBObj 的 XSD:

    清单 7. SPartyBObj 和 LivingThingBObj 的 XSD
    <xsd:element name="SPartyBObj" substitutionGroup="CommonBObj" 
         type="SPartyBObjType" />
    <xsd:complexType name="SPartyBObjType">
      <xsd:complexContent>
      <xsd:extension base="CommonBObjType">
      <xsd:sequence>
        <xsd:element ref="TCRMExtension" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="PrimaryKeyBObj" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="ComponentID" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="ObjectReferenceId" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="SPartyId" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="DisplayName" minOccurs="0" maxOccurs="1" />
        <xsd:element ref="SPartyLastUpdateDate" 
        minOccurs="0" maxOccurs="1" />
        <xsd:element ref="SPartyLastUpdateUser" 
        minOccurs="0" maxOccurs="1" />
        <xsd:element ref="SPartyLastUpdateTxId" 
        minOccurs="0" maxOccurs="1" />
        <xsd:element ref="IdentifierBObj" minOccurs="0" 
        maxOccurs="unbounded" />
        </xsd:sequence>
        </xsd:extension>
        </xsd:complexContent>
     </xsd:complexType>
    
    <xsd:element name="LivingThingBObj" substitutionGroup="CommonBObj" 
        type="LivingThingBObjType" />
    <xsd:complexType name="LivingThingBObjType">
      <xsd:complexContent>
      <xsd:extension base="SPartyBObjType"> 
      <xsd:sequence>
        <xsd:element ref="Age" minOccurs="0" maxOccurs="1"/>
        <xsd:element ref="LivingThingLastUpdateDate" 
        minOccurs="0" maxOccurs="1"/>
      </xsd:sequence>
    </xsd:extension>
    </xsd:complexContent>
    </xsd:complexType>
  2. 对于 WebService XSD,定义实体的扩展关系(见上面的 图 5)。例如,Human 扩展 LivingThing。

定制元数据

配置实体层次结构的业务对象和服务元数据是启用子类型框架的关键。这个步骤让实体子类型框架可以正确地转发服务。按以下步骤定制生成的元数据:

  1. 在 V_element 表中,按 PARENT_GRP_NAME 列建立组关系。例如:
    清单 8. 为填充元数据生成的 SQL:V_ELEMENT 表
    INSERT INTO V_GROUP 
    (GROUP_NAME, APPLICATION, OBJECT_NAME, LAST_UPDATE_DT, SORTBY) 
    VALUES ('SPartyBObj', 'TCRM', 'mdm.est.samples.component.SPartyBObj', 
    CURRENT TIMESTAMP, 'LAST_UPDATE_DT');
    
    INSERT INTO V_GROUP 
    (GROUP_NAME, APPLICATION, OBJECT_NAME, LAST_UPDATE_DT, SORTBY,
    PARENT_GRP_NAME) 
    VALUES 
    ('LivingThingBObj', 'TCRM', 'mdm.est.samples.component.LivingThingBObj', 
    CURRENT TIMESTAMP, 'LAST_UPDATE_DT', 'SPartyBObj');
    
    INSERT INTO V_GROUP 
    (GROUP_NAME, APPLICATION, OBJECT_NAME, LAST_UPDATE_DT, SORTBY, 
    PARENT_GRP_NAME) 
    VALUES ('HumanBObj', 'TCRM', 'mdm.est.samples.component.HumanBObj', 
    CURRENT TIMESTAMP, 'LAST_UPDATE_DT', 'LivingThingBObj');
  2. 在 CDBUSINESSTXTP 表中,按 PARENT_BUSINESS_TX_TP_CD 列建立事务关系。例如:
    清单 9. 为填充元数据生成的 SQL:CDBUSINESTXTP 表
    INSERT INTO CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, 
    LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD) 
    VALUES (1000013, 'addSParty',  null, null,
     CURRENT TIMESTAMP, 'Y', 'P', null, 1);
    
    INSERT INTO CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, 
    LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD, 
    PARENT_BUSINESS_TX_TP_CD) 
    VALUES (1000055, 'addLivingThing',  null, null, 
    CURRENT TIMESTAMP, 'Y', 'P', null, 1, 1000013);
    
    INSERT INTO CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, 
    LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD, 
    PARENT_BUSINESS_TX_TP_CD) 
    VALUES (1000070, 'addPet',  null, null, 
    CURRENT TIMESTAMP, 'Y', 'P', null, 1, 1000055);
  3. 在 CDINTERNALTXNTP 表中,按 PARENT_INTERNAL_BUS_TX_TP 列建立事务关系。例如:
    清单 10. 为填充元数据生成的 SQL:CDINTERNALTXNTP 表
    INSERT INTO CDINTERNALTXNTP (INTERNAL_BUS_TX_TP, NAME, DESCRIPTION, EXPIRY_DT,
    LAST_UPDATE_DT, COMPONENT_TYPE_ID) 
    VALUES (1000437, 'addSParty', null, null, CURRENT TIMESTAMP, 1000105);
    
    INSERT INTO CDINTERNALTXNTP (INTERNAL_BUS_TX_TP, NAME, DESCRIPTION, EXPIRY_DT,
    LAST_UPDATE_DT, COMPONENT_TYPE_ID, PARENT_INTERNAL_BUS_TX_TP) 
    VALUES (1000446, 'addLivingThing', null, null, 
    CURRENT TIMESTAMP, 1000147, 1000437);
    
    INSERT INTO CDINTERNALTXNTP (INTERNAL_BUS_TX_TP, NAME, DESCRIPTION, EXPIRY_DT,
    LAST_UPDATE_DT, COMPONENT_TYPE_ID, PARENT_INTERNAL_BUS_TX_TP) 
    VALUES (1000440, 'addHuman', null, null, 
    CURRENT TIMESTAMP, 1000121, 1000446);
  4. 如果事务参与实体子类型框架,那么在 INTERNALTXREQRESP 表中创建它的元数据。这是 Master Information Hub, Version 9 中新增的表。例如,对于 addSParty,添加以下元数据:
    清单 11. 为填充元数据生成的 SQL:INTERNALTXREQRESP 表
    INSERT INTO INTERNALTXREQRESP (INTERNTX_REQRESP_ID, INTERNAL_BUS_TX_TP,
     APPLICATION,
    GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, 
    LAST_UPDATE_USER,LAST_UPDATE_DT, COLLECTION_IND)
    VALUES (1000460, 1000437, 'TCRM', 'SPartyBObj', 'I', null, null, 1, 
    'cusadmin', 
    	CURRENT TIMESTAMP, null);
    
    INSERT INTO INTERNALTXREQRESP (INTERNTX_REQRESP_ID, INTERNAL_BUS_TX_TP,
     APPLICATION,
    GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER,
    LAST_UPDATE_USER,LAST_UPDATE_DT, COLLECTION_IND)
    VALUES (1000461, 1000437, 'TCRM', 'SPartyBObj', 'O', null, null, null, 
    'cusadmin', 
    	CURRENT TIMESTAMP, 'N');

引入包含单一类型层次结构中多个类型的实例的实体

业务对象可以包含属于同一类型层次结构的其他业务对象。例如,CommunityBObj 可以包含一个或多个 SPartyBObj、PetBObj、LivingThingBObj 和 HumanBObj 业务对象,或者其他扩展子类型业务对象。我们来看看支持这一需求的最佳实践:

  • 在容器 BObj 中引入根实体类型的设置器和获取器方法。例如,在 CommunityBObj 中引入 SPartyBObj 的设置器和获取器方法:
    清单 12. 在 CommunityBObj 中引入 SPartyBObj 的设置器和获取器方法
    public class CommunityBObj extends TCRMCommon  {
        protected Vector<SPartyBObj> vecSPartyBObj;
    
        public Vector getItemsSPartyBObj() {
          return vecSPartyBObj;
        }
    	
        public void setSPartyBObj(SPartyBObj sPartyBObj) {
          this.vecSPartyBObj.add(sPartyBObj);
        }
        ......
    }
  • 在定义 RMI 服务的 XSD 中,确保为 SPartyBObj 定义的元素的 abstract 属性设置为 true。为这个业务对象定义的元素(在这里是 CommunityBObj)作为 SParty 的所有子类型的容器,必须使用 ref 属性引用它。对于类型层次结构中的每个实体,元素定义中必须有 substitutionGroup 属性,它赋值为 abstract 元素 SPartyBObj,见清单 13 中的粗体代码:
    清单 13. XSD:作为抽象元素引入 SPartyBObj
    <xsd:element name="SPartyBaseBObj" abstract="true" substitutionGroup="CommonBObj" 
         type="SPartyBaseBObjType"/>
    <xsd:complexType name="SPartyBaseBObjType" >
      <xsd:complexContent>
        <xsd:extension base="CommonBObjType"/>
      </xsd:complexContent>
    </xsd:complexType>
    
    <xsd:element name="CommunityBObj" substitutionGroup="CommonBObj" 
        type="CommunityBObjType" />
    <xsd:complexType name="CommunityBObjType">
    <xsd:complexContent>
    	<xsd:extension base="CommonBObjType">
    	<xsd:sequence>
    	 ......
    	 <xsd:element ref="SPartyBaseBObj" minOccurs="0" 
    	 maxOccurs="unbounded"/>
    	 <xsd:element ref="TCRMExtension" minOccurs="0" maxOccurs="1"/>
    	 <xsd:element ref="PrimaryKeyBObj" minOccurs="0" maxOccurs="1"/>
       </xsd:sequence>
    </xsd:extension>
    </xsd:complexContent>
    </xsd:complexType>
    
    
    <xsd:element name="SPartyBObj" substitutionGroup="SPartyBaseBObj" 
        type="SPartyBObjType" />
    <xsd:complexType name="SPartyBObjType">
      <xsd:complexContent>
      <xsd:extension base="SPartyBaseBObjType">
      ......
    
    <xsd:element name="LivingThingBObj" 
    substitutionGroup="SPartyBaseBObj" 
        type="LivingThingBObjType" />
    <xsd:complexType name="LivingThingBObjType">
      <xsd:complexContent>
      <xsd:extension base="SPartyBObjType">
      ......
    
    <xsd:element name="HumanBObj" substitutionGroup="SPartyBaseBObj" 
        type="HumanBObjType" />
    <xsd:complexType name="HumanBObjType">
      <xsd:complexContent>
      <xsd:extension base="LivingThingBObjType">
      ......

在子类型实体上创建扩展子类型和数据扩展

有时候,需要对层次结构中的实体进行扩展或进一步子类型化,比如您编写自己的应用程序,希望客户可以进一步扩展应用程序的实体。在可以访问应用程序源代码的情况下,没有必要使用这两种扩展模式。本节讨论这种场景。

对于现有的实体类型层次结构,可以:

  • 对层次结构中现有的任何实体进一步子类型化
  • 扩展层次结构中的叶实体

例如,可以在 Human 下面引入子类型 Male。应该按照前面描述的步骤实现这个新的子类型。尽管 Male 的服务在它自己的控制器中,但是实体子类型框架在转发服务时能够找到它们。图 10 中的类图说明新的子类型 Male 的类关系:

图 10. 新的子类型 Male 的类图
这个图说明当进一步子类型化类型层次结构的叶节点时影响到的主要组件。MaleTxnBean 事务控制器组件类实现 MaleTxn 接口。addMale 和 updateMale 服务在这个接口中定义。MaleFinder 发现器控制器类实现 MaleFinder 接口。getMale 服务在这个接口中定义。MaleComponent 业务组件类实现 Male 接口。实现服务背后所有业务逻辑的 addMale、updateMale 和 getMale 服务在这个接口中定义。MaleBObj 业务对象类扩展 HumanBObj 业务对象

要想扩展类型层次结构中的叶实体(例如对 MaleBObj 引入 XMaleBObjExt),只需采用 InfoSphere Master Information Hub /MDM Server Workbench 提供的标准数据扩展模式。(注意:到 Version 9.0 为止,只有叶节点允许数据扩展。关于数据扩展的更多信息,请参见 InfoSphere Master Information Hub or MDM Server Developer's Guide。


结束语

本教程介绍了实体子类型的概念。讨论了如何为 InfoSphere Master Information Hub 和 InfoSphere Master Data Management Server 实现新的和扩展的实体子类型及相关服务。现在您应该掌握了如何为使用 Master Information Hub 创建的新领域实现服务互操作性和可扩展性。还应该掌握了如何定制子类型实体和服务的实现。

致谢

作者要感谢同事 Paul van Run 和 Lena Woolf,感谢他们为本教程提供了宝贵的建议和反馈。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=483211
ArticleTitle=在 IBM InfoSphere Master Information Hub 中引入实体子类型
publish-date=04162010