[转载]WebSphere 4.0 中的 EJB 元数据: 第 2 部分:关联

WebSphere 4.0 中的 EJB 元数据: 第 2 部分:关联


简介

我的上篇文章描述了在 WebSphere® Application Server 高级版 4.0 中,如何将容器管理的持久性(CMp)EJB 属性通过一组三个 XML 文件映射到关系数据库的列中:

  • EJB-JAR 文件,描述 EJB 及其容器管理的属性。
  • 模式 XML 文件,描述 EJB 将要映射到的数据库模式。
  • 映射 XML 文件,描述如何将 EJB 中的属性映射到数据库模式中的列。

那 篇文章没有描述关于 EJB 关系的任何内容。一个 EJB 引用另一个 EJB 的能力以及将那些关系映射到关系数据库中外键的能力是 VisualAge® for Java™ 和 WebSphere Application Server 3.5 中 EJB 实现的主要优势之一。该优势在 Application Server 4.0 和 WebSphere StudioApplication Developer 中已经得到改进。正如您在阅读上篇文章后可以想象的那样,描述这些关系的元数据现在也可以用与存储属性列映射相同的方法存储在 XML 文件中。我们将在本文中探讨这些文件并帮助您理解 Application Developer 和 Application Server 4.0 的工作原理。

但是,在查看 Application Server 4.0 中文件的详细信息之前,我们先讨论一下 EJB 2.0 规范。虽然我们讨论的是 EJB 规范,但是您将会获得一些概念,它们将帮助您理解如何在 Application Server 4.0 中实现关系。Application Server 4.0 只实现 EJB 1.1 规范,但它还以兼容的方式实现 EJB 2.0 中的许多思想。




回页首


EJB 2.0 关系

去 年关于 J2EE 领域最引人注目的新闻可能是 EJB 2.0 最终发行版 2 规范 [Sun] 的发布。那些不象关注最喜爱的体育比分那样时刻关注 Sun 规范发布的人们现在可能会摇头并询问,“为什么将它称为最终发行版 2?第一个‘最终发行版’真的是最终的吗?”好吧,这里有关于我们问题的一些历史。

EJB 2.0 规范的第一个“最终发行版”(以及 2.0 规范以前的草案)将一种特殊的二分法引入到了 EJB 的世界中。这个二分法必须处理 EJB 和一种称为 依赖对象的 特殊事物之间的差别。在 Sun 第一次发布这个规范的时候,给供应商的建议是不赞成使用实体 bean 之间的对象-与-对象关系。取而代之的是,对象-与-对象关系就象下面图 1 中 Customer 与 Address 有关系这一标准示例一样,是通过使用一组称为依赖对象的不同的类来实现的。这不完全是一个糟糕的想法 ? 这样设计的主要原因是因为依赖对象将是本地的(并且不象 EJB 那样是分布式的),在理论上,容器的供应商可以将一些“智能”构建到容器中。然后这个容器就可以通过 EJB 中无法实现的方法对这些对象进行高速缓存和智能管理,因为 EJB 的客户机无法知道 EJB 对其地址空间来说是本地的还是位于网络之外的其它一些 EJB 容器内。


图 1. 简单的 1-1 关系
简单的 1-1 关系

当 不同的应用程序服务器供应商预览这个规范时,他们发现这不是表示关系的最优方法。不仅开发人员理解起来很复杂,而且供应商实现起来也是一个很大的挑战。因 此供应商请求 Sun 进行修改。经过一些会议和电子邮件交流之后,去除了原来想法中一些过时的东西并进行了复查。这次雷厉风行的行动使这个规范显著简化。去掉了依赖对象,并且 重新引入了 EJB-与-EJB 关系。

在最终的 EJB 2.0 规范中,通过在 EJB 部署描述符(EJB DD)中使用一组简单的关系声明,EJB 就相互联系起来。处理关系的代码由 EJB 实现中的容器生成,因而其它 EJB 也可以遍历和操作这些关系。获取本地性能优势的关键是通过部署 EJB 的新方法:EJB 2.0 中,可以将其部署为 远程或者 本地EJB。如果 EJB 是本地的,那么供应商可以使用已经能够用于依赖对象的相同类型的优化, 而无须改变底层编程模型。这个最后一点怎么强调都不过分。所有 EJB(本地或者远程)的单一、统一的编程模型和抽象 XML 描述是 EJB 2.0 规范的核心。

现在回到我们的主题。EJB 2.0 规范指出,实体 EJB 可以相互联系,而关系在 EJB 2.0 DD 中进行描述。这在 EJB 2.0 规范中看上去如何呢?让我们来看下面的摘录,它取自用于上述简单 Customer-Address 示例的 DD。


...



Customer

com.ibm.ejb.CustomerLocalHome com.ibm.ejb.CustomerLocal
?



Address

com.titan.address.AddressLocalHome
com.titan.address.AddressLocal
?

?



Customer-Address


Customer-For

One


Customer



homeAddress




Address-of

One


Address







(本示例改编自 Richard Monson-Haefel 编写的 Enterprise JavaBeans™,第三版,它更详细地描述了这个示例。该书还很好地论述了 EJB 2.0 规范和 EJB 2.0 关系操作的方法。)

将 EJB 2.0 实现的许多复杂性(在 [Monson-Haefel] 中描述)撇开不管,有几个要点需要分析一下,它们是关于这个 DD 中表示 Customer 和 Address 之间关系的方法。

节定义了名为 Customer 和 Address 的两个 EJB 并描述了它们的 home 接口和本地接口。(这两个 EJB 都是本地的 ? 有关详细信息请再次查阅 [Monson-Haefel]。)更有趣的节是 节,尤其是单一 样本。EJB 关系中有一些特别的地方需要您理解:

  • 两个 EJB 之间每个已命名的 关系都包含两个 角色
  • 每个角色都有一个 名称(name)、一个 多重性(multiplicity)和一个向后引用 节中 EJB 的 源(source)
  • 角色可能包含一个 ,它是除 以外添加到 EJB 的一个特殊字段,是容器管理的 EJB 的常规持久性字段。如果角色中出现 标记,那么这个关系可以从一端的 EJB 遍历到该关系另一端的 EJB。

对于那些更喜欢可视化表示的人来说,下面的图 2 显示了 ejb-jar.xml 文件的不同部分是如何相互关联的。


图 2. EJB 2.0 关系定义
EJB 2.0 关系定义



回页首


WebSphere Application Server 4.0 中关系的实现

既 然 Application Server 4.0 只实现 EJB 1.1 规范而不实现 EJB 2.0 规范,那我们还能在 Application Server 4.0 中做些什么呢?Application Server 和 Application Developer 开发团队决定采用一种在体系结构上与 EJB 2.0 兼容的路线(这使我们以后编写转换工具更容易),但仍在 EJB 1.1 的限制范围内。我们必须提供一种方法来表示 EJB 2.0 所要求的关系元数据,但我们不能在 EJB 1.1 XML DD 内完成,因为这个规范禁止添加新的节。要包含这类信息,我们将第五个文件添加到上篇文章中描述的“四个文件的故事(tale of four files)”中。这个文件,通常称为 EJB 扩展文件,被命名为 ibm-ejb-ext.xml ,它包含三种超越 EJB 1.1 规范范围的信息:

  • 关联,包含 EJB 2.0 DD 中描述的相同类型的角色和多重性信息。
  • 只读的读方法的访问标志,当读取但不更新实体 EJB 实例时,要确保它们未被标记为 dirty 并没有不必要地继续保存在数据库中。
  • SQL 或者 EJB-QL,用来实现定制查找程序方法。这在 [Brown 2001] 和 Application Developer 文档中有描述。

要 理解其工作原理,查看下面示例。使用 Application Developer 可以生成这些文件,方法是通过打开 EJB JAR 项目上的 EJB Extensions Editor,然后将 Customer 和 Address EJB 之间的关系添加到 Relationships 页面。这个过程已经在别处讲述过,所以我不再重复,我要说的是将向您显示这个示例的 Relationships 页面(参阅下图 3)。(这个页面定义了两个关系:Customer-to-Address 和 Order-to-lineItem。我们将在下面讨论第二个关系)。


图 3. Customer-to-Address 的 Relationships 页面
Customer-与-Address 的 Relationships 页面

当您创建这个关系时,Application Developer 将创建或更新这个 EJB Jar 文件的扩展文件。这个扩展文件将向后引用 ejb-jar.xml 文件(EJB 1.1. DD)内的元素。它还将一个或多个 cmp 字段添加到 EJB 中(稍后将有更多信息)。要理解扩展文件的工作原理,首先让我们介绍一下用于我们示例的部分标准 EJB 1.1 DD(为清晰起见除去了某些部分 ? 它们将在下面描述)。


JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">

projectForWSDD
?


Customer
com.ibm.demo.ejbs.CustomerHome
com.ibm.demo.ejbs.Customer
com.ibm.demo.ejbs.CustomerBean
Container
java.lang.String
False

customerId


name


address_addressId

customerId

ejb/Address
Entity
com.ibm.demo.ejbs.AddressHome
com.ibm.demo.ejbs.Address
Address



Address
com.ibm.demo.ejbs.AddressHome
com.ibm.demo.ejbs.Address
com.ibm.demo.ejbs.AddressBean
Container
java.lang.String
False

addressId


street


city


state


zip

addressId

ejb/Customer
Entity
com.ibm.demo.ejbs.CustomerHome
com.ibm.demo.ejbs.Customer
Customer




您 可能记得上一篇文章中,Application Developer 添加到 EJB DD 的主要内容是唯一标识 DD 内每个元素的标识属性。不仅上篇文章中我们分析的映射 XMI 文件需要这个标识,而且扩展文档也需要它。看过 EJB DD 之后,现在准备分析一个简单的 EJB 扩展文件。


xmlns:xmi="http://www.omg.org/XMI" xmlns:ejbext="ejbext.xmi"
xmlns:ejb="ejb.xmi" xmlns:ecore="ecore.xmi" xmi:id="ejb-jar_ID_Ext">
xmi:id="Customer_Ext">
href="META-INF/ejb-jar.xml#Customer"/>
name="address" sourceEjbName="Address" forward="true"
navigable="false" relationship="EjbRelationship_1">




xmi:id="Address_Ext">
href="META-INF/ejb-jar.xml#Address"/>
name="customer" sourceEjbName="Customer" forward="false"
navigable="true" relationship="EjbRelationship_1">




name="Customer-to-Address"
relationshipRoles="EjbRelationshipRole_2 EjbRelationshipRole_1"/>


让我们简要查看一下这个 XML 文件的结构。它与我们上面分析的 EJB 2.0 DD 节类似,但并不相同。特别是,每个 EJB 都有一个与之相对应的 元素。这个在 对象中扩展的特殊 EJB 由对 EJB-JAR.XML 文件中实体元素的 XML 引用(一个 href)所引用。例如,Customer_Ext 元素通过下列行来引用 Customer EJB:

  href="META-INF/ejb-jar.xml#Customer"/>

元素还包含(对 EJB 参与的每个独立的关系而言)一个 localRelationshipsRoles 元素。这个元素包含一个多重性并且可能包含一个属性元素,它与 EJB 2.0 规范中的 元素的作用几乎相同,但有一个非常重要的差别。由于 元素在 EJB 1.1 中不可用(而所有容器管理的字段必须描述成 元素),所以 Application Developer 必须添加一个新的 属性以包含对相关 EJB 的引用。在我们的实例中,Application Developer 在 Customer EJB 中添加了一个名为 address_address_id 的新属性。该属性显示在 EJB 扩展文件的 元素中,它包含对如下所示的 Address 实体元素中特殊 CMp 字段的引用:



EJB 2.0 规范和 Application Server 扩展文件之间的另一个差别是关系的定义移到了 EJB 文件的底部。在这种情况下,每个关系声明为对两个角色的引用,每个角色在 EJB 的 元素内进行声明。与前面的一样,下图 4 说明了这两个文件的不同部分之间的关系。


图 4. WebSphere Application Server 4.0 关系定义
WebSphere Application Server 4.0 关系定义

当您研究这个示例时,您可以看到 EJB 2.0 规范中的所有元素 ? 关系、角色、多重性和关系属性 ? 不是出现在 Application Server EJB 1.1 DD 中,就是出现在 Application Server EJB 扩展文件中。




回页首


更复杂的关系

既 然您已经知道了在 EJB 扩展文件和 EJB DD 中如何表示 0..1 与 0..1 关系,那么您已经为学习更复杂的关系准备就绪。您将发现它们与上一个示例非常类似。考虑 EJB 2.0 规范的一个标准示例 ? Order 和 Order 上的 lineItem 之间的关系。


图 5. Order 和 lineItem
Order 和 line Item

在 这个关系中,由于每个 Order 将指向 N 个 lineItem,根据我们所知的在 Application Server 较早版本中处理 EJB 关系的方法以及 EJB 2.0 规范中描述 EJB 关系的方法,我们可以预知几件事情。我们可以预知每个 Order 将引用一个 lineItem 的 Collection(通过 getlineItems() 方法)。这里是 Application Developer 中创建这个关系的关系页面,如下图 6 所示。


图 6. Order-to-lineItem 关系
Order-to-lineItem 关系

既然您已经知道了这个关系,那么可以研究上面的 EJB DD 中没有讨论过的节。


Order
com.ibm.demo.ejbs.OrderHome
com.ibm.demo.ejbs.Order
com.ibm.demo.ejbs.OrderBean
Container
java.lang.String
False

dateplaced


orderId

orderId

ejb/lineItem
Entity
com.ibm.demo.ejbs.lineItemHome
com.ibm.demo.ejbs.lineItem
lineItem



lineItem
com.ibm.demo.ejbs.lineItemHome
com.ibm.demo.ejbs.lineItem
com.ibm.demo.ejbs.lineItemBean
Container
java.lang.String
False

itemId


price


description


order_orderId

itemId

ejb/Order
Entity
com.ibm.demo.ejbs.OrderHome
com.ibm.demo.ejbs.Order
Order



这里您将会注意到 Order 中没有新的 CMp 字段,因为 lineItem 的 Collection 不是订单的容器管理的字段。换言之,集合本身在数据库中不是持久性的,而是当接收到 getlineItems() 方法时,由数据库生成的。但是,CMp 字段已经被添加到 lineItem 来表示 lineItem 及其关联的订单之间的连接。这反映这样的事实:在关系数据库中,1 与 0..N 关系是由“0..N”端表中的“向后指针”或外键指向“1”端的表来表示的(有关这个关系的详细描述请查阅 [Brown 2000])。同样,现在您可以研究上面 EJB 扩展文件中没有讨论的引用这些 EJB 的节。

  xmi:id="Order_Ext">
href="META-INF/ejb-jar.xml#Order"/>
name="lineItems" sourceEjbName="lineItem" forward="false"
navigable="true" relationship="EjbRelationship_2">


xmi:id="lineItem_Ext">
href="META-INF/ejb-jar.xml#lineItem"/>
name="order" sourceEjbName="Order" forward="true"
navigable="true" relationship="EjbRelationship_2">




relationshipRoles="EjbRelationshipRole_3 EjbRelationshipRole_4"/>

如 上所述,您会看到扩展文件为关系中的每个 EJB 定义了一个角色,然后将关系定义为这两个角色的连接。同样,lineItem 扩展定义它到 order_order_id 属性(定义在 EJB DD 中)的连接。可以在 lineItem EJB 的 multiplicity 行中找到有关这部分 EJB 扩展文件的唯一奇怪的信息:



多重性的上限(-1)实际上指一个无界的多重性,或者一个“N”多重性。正如您可以推测,XML 属性的合法值是 0、1 或者 -1。




回页首


将关系映射到数据库外键

上篇文章讨论了 Application Server 和 Application Developer 如何使用称为 Schema.dbxmi 的 XML 文件来表示映射到 EJB 设计的关系数据库模式。事实上,这种格式只在 Application Developer 的 beta 版本和初始版本之间稍微作了更改。您可能记得上篇文章中该文件有如下格式。


...description of the database schema information (derivation, etc.)


...description of the relational database table


Application Developer 现在将所有模式分成一组包含如下形式的文件: Schema.dbxmi 包含一个对“schemata”文件(包含上述 元素)的引用集和 N 个称为 "TableName".tblxmi 的文件(包含上述 元素)。对于我们的示例,以自顶向下的映射方式生成的 Schema.dbxmi 文件看起来象这样。


xmlns:xmi="http://www.omg.org/XMI"
xmlns:RDBSchema="RDBSchema.xmi" xmi:id="RDBDatabase_1" name="SAMpLE">








正 如您看到的,在我们的示例中每个 EJB 都有一个表文件。这些表与 EJB 有相同的命名,这对于自顶向下映射来说是标准的。这些文件的其它所有方面与我们在上篇文章中讨论的几乎相同,所以这里我们就不再描述了。取而代之的是,我 们将看一下其中的一个文件(Customer Table 的表 XMI 文件)来向您显示关联添加的一个附加特性。如果您查看这个文件的顶部,就会发现下面附加的信息部分。

   group="RDBReferenceByKey_1">
xmi:id="SQLCharacterStringType_3" length="250">
href="JavatoDB2UDBNT_V72TypeMaps.xmi#SQLCharacterStringType_250"/>


xmi:id="SQLReference_1" name="CUSTOMERpK" members="RDBColumn_1"
table="RDBTable_1" constraint="Constraint_CUSTOMERpK"/>
xmi:id="RDBReferenceByKey_1" name="ADDRESS" members="RDBColumn_3"
constraint="SQLConstraint_1">



稍微做点简化,通过 元素的引用,将列(Address_AddressId)定义为一个到 Address Table 的外键。理解这些外键的定义是理解 EJB 关系映射的关键。上篇文章描述了 map.mapxmi 文件,它定义 EJB DD 中的 元素应如何映射到关系数据库模式中的字段。首先,针对我们的示例分析 XMI 文件的如下元素,接着我们将讨论如何使用它来将 EJB 关系映射到前面定义过的外键:


xmi:id="ForwardFlattenedFKComposer_2"/>
href="META-INF/ibm-ejb-jar-ext.xmi#EjbRelationshipRole_2"/>
href="META-INF/ibm-ejb-jar-ext.xmi#EjbRelationshipRole_1"/>
href="projectForWSDD/ejbModule/META-INF/Schema/
SAMpLE_NulliD_CUSTOMER.tblxmi#RDBReferenceByKey_1"/>


这 些文件让我们接近我们旅程的终点,并找到问题的症结所在。我们已经知道 EJB 扩展文件如何定义关系角色以及这些角色可能如何映射到 EJB DD 中的属性。我们还知道如何在模式文件中表示外键。本部分将所有这些都联系起来。这里我们看到 Customer 的 Address 字段映射用表模式文件中的外键引用将关系的两部分链接在一起。EJB 扩展文件、Address 表模式文件和映射文件之间的交互如下图 7 所示,它说明这三个文件的连接。


图 7. 将关系映射到外键
将关系映射到外键

您还未看到的唯一内容是将 Order 和 lineItem 连接在一起的映射元素。正如您可以想象到的,它与将 Customer 和 Address 连接在一起的前一节非常类似:


xmi:id="ForwardFlattenedFKComposer_1"/>
href="META-INF/ibm-ejb-jar-ext.xmi#EjbRelationshipRole_4"/>
href="META-INF/ibm-ejb-jar-ext.xmi#EjbRelationshipRole_3"/>
href="projectForWSDD/ejbModule/META-INF/Schema/
SAMpLE_NulliD_liNEITEM.tblxmi#RDBReferenceByKey_1"/>


此外,该元素所做的全部就是将构成 EJB 关系的两个关系角色链接在一起,然后用数据库中表示关系的外键将它们连接在一起。




回页首


结束语

深 呼吸,然后放松。这真是一次漫长的旅行,您已经看到了许多详细的技术信息,但是现在您应该理解用于 Application Developer 和 Application Server 在 EJB 映射中使用的 XML 文件的功能和交互作用。这样可以获得来自 Application Developer 的“魔力”,并且帮助您解决使用这些工具时的映射问题。

请使用浏览器的分享功能分享到微信等