paulwong

          CMR(Container Management Relationship)

          前面兩期我們提到entity beanJ2EE架構中是用來塑模business object的元件,它同時也是在business tier保存資料的技術之一,它被用來存取保存在EIS tier(Enterprise Information System)的資料,而目前運用的最為普遍的EIS技術則是關聯式資料庫。在關聯式資料庫中,我們以所謂的E-R model(Entity Relationship)來定義表格之間的關係,而這些關係是利用主鍵(Primary Key)與外鍵(Foreign Key)的宣告來表示。由於entity bean所要存取的關聯式資料庫的表格之間有關係存在,因此EJB必須發展出相應的技術來處理entity bean之間的關係,這就是EJB2.0版後提出的CMR(Container Management Relationship)所要處理的問題。

          CMP相同,我們是透過所謂的Abstract Schema Persistence/Abstract Programming Model來定義entity beanCMR,這表示我們不需要撰寫存取資料庫的程式碼,我們只需要分別在部署描述子(Deployment Descriptor)bean class中定義entity bean之間的關係,container的部署工具就會在部署時期會自動產生相應的程式碼。下面我們將以MemberAddress兩個entity bean為例子,實際說明CMR的重要觀念與實作方式。

          <enterprise-beans>

          <entity>

              <ejb-name>Member</ejb-name>

              <local-home>com.eland.ejb.MemberLocalHome</local-home>

              <local>com.eland..ejb.MemberLocal</local>

              <ejb-class>com.eland.ejb.MemberBean</ejb-class>

              <persistence-type>Container</persistence-type>

              <prim-key-class>java.lang.String</prim-key-class>

              <reentrant>False</reentrant>

              <cmp-version>2.x</cmp-version>

              <abstract-schema-name>Member</abstract-schema-name>

              <cmp-field><field-name>userid</field-name></cmp-field>

              <cmp-field><field-name>username</field-name></cmp-field>

              <cmp-field><field-name>password</field-name></cmp-field>

              <primkey-field>userid</primkey-field>

          </entity>

          <entity>

              <ejb-name>Address</ejb-name>

              <local-home>com.eland.ejb.AddressLocalHome</local-home>

              <local>com.eland.ejb.AddressLocal</local>

              <ejb-class>com.eland.ejb.AddressBean</ejb-class>

              <persistence-type>Container</persistence-type>

              <prim-key-class>java.lang.String</prim-key-class>

              <reentrant>False</reentrant>

              <cmp-version>2.x</cmp-version>

              <abstract-schema-name>Address</abstract-schema-name>

              <cmp-field><field-name>type</field-name></cmp-field>

              <cmp-field><field-name>city</field-name></cmp-field>

              <cmp-field><field-name>street</field-name></cmp-field>

              <primkey-field>type</primkey-field>

          </entity>

          </enterprise-beans>

           首先我們要說明定義CMR時必須了解的四個概念,關係(Relationship)、角色(Role)、多數性(Multiplicity)、可視性(Navigability)。下圖顯示了這四個概念的關係:

           

          1.       <![endif]> 關係

          關係表示entity bean之間的連結。在我們的例子中,關係的名字為Member-Address

          2.       角色

          每一個關係都有兩個角色,分別代表entity bean連結的兩個方向。角色有其名稱,在我們的例子中,兩個角色分別叫做theMemberaddresses

          3.       多數性

          意指對一角色而言有多少entity bean能夠參與該關係。兩個entity bean之間能夠存在的關係有一對一、一對多、多對一、多對多等。在我們的例子中,MemberAddress之間具有一對多關係,這表示一個Member bean可以有多個Address bean與其連結。我們通常以多數性來決定角色的名稱,以我們的例子而言,由於MemberAddress具有一對多關係,因此我們將定冠詞the加在Member之前,而以複數型的addresses命名Address

          4.       可視性

          意指一角色是否能夠透過關係被直接存取。可視性可以是單向的,也可以是雙向的。在我們的例子中,箭頭指向的角色是可視的,而這裡的可視性是單向的。從MemberAddress的方向來看,addresses這個角色是可視的,而從AddressMember的方向來看,theMember這個角色是不可視的。若一個角色是可視的,則其相關的entity bean必須有local interface。一個沒有local interfaceentity bean只能與另一個有local interfaceentity bean建立單向的關係。

           接下來我們要看如何在部署描述子中運用上面提到的概念定義CMR。下面是Member-Address這組單向的一對多關係在部署描述子中的定義方式:

           <relationships>

                  <ejb-relation>

                  <ejb-relation_name>Member-Address</ejb-relation-name>

                  <ejb-relationship-role>

                  <ejb-relation-role-name>theMember</ejb-relation-role-name>

                  <multiplicity>Many</multiplicity>

                  <cascade-delete/>

                  <relationship-role-source>

                  <ejb-name>Address</ejb-name>

          </relationship-role-source>

          </ejb-relationship-role>

                  <ejb-relationship-role>

                  <ejb-relation-role-name>Address</ejb-relation-role-name>

                  <multiplicity>One</multiplicity>

                  <relationship-role-source>

                  <ejb-name>Member</ejb-name>

          </relationship-role-source>

          <cmr-field>

                  <cmr-field-name>addresses</cmr-field-name>

                  <cmr-field-type>java.util.Collection</emr-field-type>

          </cmr-field>

          </ejb-relationship-role>

          </ejb-relation>

          </relationships>

           各標籤的意義如下:

          1.    <relationships>標籤在部署描述子中位於<enterprise-beans><assembly-descriptor>標籤之間,一個部署描述子中只能有一個<relationships>標籤。

          2.    <relationships>標籤內可以有多組<ejb-relation>標籤,分別定義不同的CMR。每一組<ejb-relation>標籤內可以有一組<ejb-relation-name>標籤用來定義關係名稱。每一組<ejb-relation>標籤內必須有兩組<ejb-relationship-role>標籤用來定義該關係的兩個角色。

          3.    <ejb-relationship-role>標籤內的<ejb-relation-role-name>標籤用來定義角色名稱。

          4.    <ejb-relationship-role>標籤內的<relationship-role-source>標籤定義了該角色所參照(reference)entity bean的名稱。在我們的例子中,theMember這個角色所參照的entity beanAddress

          5.    <relationship-role-source>標籤內的<ejb-name>標籤必須存在於同一個部署描述子的<enterprise-beans>標籤中,亦即一CMR的兩個角色所參照的entity bean必須在同一個EJB模組中。

          6.     <ejb-relationship-role>標籤內的<multiplicity>標籤用來定義該角色所參照的entity bean是一個(One)或多個(Many)

          7.     如果一個角色是可視的,則必須定義<cmr-field>標籤CMR<cmr-field>標籤內的<cmr-field-name>標籤用來定義CMR的名稱,CMR的名稱必須以小寫開頭,且依慣例與角色名稱相同。每一個<cmr-field-name>在其所參照的bean class裡都必須有抽象的getter/setter方法與其對應,EJB規格書中將這些方法叫做CMR fields

          8.     由於theMemberaddresses具有一對多的關係,因此addresses的型態必須是其local interface的集合,我們必須用<cmr-field-type>標籤定義其型別為java..util.Collectionjava.util.Set(不允許重覆)

          9.      theMember這個角色中的<cascade-delete>標籤意謂著若刪除一個Member bean,則其所參照的Address bean也會被刪除,如此可以避免在資料庫裡遺留不會再被使用到的資料。這個標籤可以用於一對一與一對多關係,但不能用於多對一與多對多關係。

          以上是一對多關係在部署描述子中的定義方式。若關係為一對一,則兩個角色的<multiplicity>標籤都必須定義為One,且都不需要定義<cmr-field-type>標籤;若關係為多對多,則兩個角色的<multiplicity>標籤都必須定義為Many,且兩者的<cmr-field-type>標籤型態都必須定義為java.util.Collectionjava.util.Set。多對一關係同一對多關係。

          前面提到,部署描述子中的<cmr-field>標籤必須在bean class中有CMR fields與其對應。宣告CMR fields時必須遵循下列事項:

          1. CMR fields的命名格式為get<cmr-field-name>()set<cmr-field-name><cmr-field-name>的值的第一個字母改為大寫,例如getAddress()setAddress()

          2.  get<cmr-field-name>()方法的回傳型態必須與傳入set<cmr-field-name>()方法的參數型態一致。型態必須是其所參照的entity beanlocal interfacelocal interface的集合型態(java.util.Collectionjava.util.Set)

          值得注意的是,使用CMR fields並非如同使用CMP fields一樣實際存取資料庫裡的資料,而是參照到其他entity bean(setter方法)或取得所參照的entity beanlocal interface reference(getter方法)。因此呼叫一個CMP beanCMR fields,並不會改變資料庫裡的資料,而是改變兩種具有CMR關係的entity bean之間的參照狀態。接下來我們要看一些實際使用CMR fields的例子:

          public abstract class MemberBean implements javax.ejb.EntityBean {

                  // CMR fields

          public abstract java.util.Collection getAddress();

          public abstract void setAddress(java.util.Colletion address);

          // Business methods

          public void addAddress(String type, String city, Sring street) {

          InitialContext ctx = new InitialContaxt();

          AddressHomeLocal addressHome = ctx.lookup(“AddressHomeLocal”);

          AddressLocal address = addressHome.create(type, city, street);

          Collection addressHomes = this.getAddress();

          addressHomes.add(address);

          }

          public void updateAddress(String type, String city, String street) {

                  Collection addressHomes = this.getAddress();

          Iterator iter = addressHomes.iterator();

          while(iter.hasNext()) {

                  AddressLocal address = (AddressLocal)iter.next();

                  if(address.getType.equals(type)) {

                          address.setCity(city);

                          address.setStreet(street);

                          break;

          }

          }

          }

          public void removeAddress(String type) {

                  Collection addressHomes = this.getAddress();

                  Iterator iter = addressHomes.iterator();

          while(iter.hasNext()) {

                  AddressLocal address = (AddressLocal)iter.next();

                  if(address.getType.equals(type)) {

                          iter.remove(addess);

                          break;

          }

          }

          }

          }

          1.  由於MemberAddress具有一對多關係,且AddressMember而言具有可視性,因此我們在Memebr bean class中宣告一組CMR fields,該CMR fieldsjava.util.Collection為其回傳型態與參數型態。

          2.   在上面的範例中,我們宣告了三個使用getAddress() CMR fieldbusiness methodsaddAddress()方法新增一個Address bean,並建立該entity beanMember bean之間的關係,意即在使用getAddress() CMR field所取回的集合中新增一個Address beanlocal interface reference,而updateAddress()方法與removeAddress()方法則在使用getAddress() CMR field取回的集合中找到合乎條件的Address beanlocal interface reference,然後修改或刪除。需要注意的是iter.remove(address)這行程式碼並沒有真的刪除address這個local interface reference所代表的entity bean,被刪除的是entity beanentity bean之間的參照,而不是entity bean或資料庫裡的資料。

          3.  使用setAddress() CMR field要特別注意,因為它意謂著清除原來集合中所有local interface references,另以新的local interface references取代。舉例而言,如果要將兩個不同的Member bean所參照的Address bean對換,我們可以以下面的例子為之:

          Collection addressHomesA = memberA.getAddress();

          memberB.setAddress(addressHomesA);

          但如果只是要將原先為memberA所參照到的一個Address beanmemberA移到memberB,那我們必須先取得該Address beanlocal interface reference後,再將其加入memberB所參照的Address beanlocal interface references的集合,示範如下:

          Collection addressHomesA = memberA.getAddress();

          Collection addressHomesB = memberB.getAddress();

          Iterator iter = addressHomesA.iterator();

          while(iter.hasNext()) {

          AddressLocal addressA = (AddressLocal)iter.next();

          if(// Condition) {

                  addressHomesB.add(addressA);

                  break;

          }

          }

          4.   除了上面的business methods外,我們也可以在新增一個entity bean時,在bean classcreate方法中使用CMR fields建立或變更與其他entity bean的參照。依照EJB規格書規定,這必須在ejbPostCreate()方法中為之。

          CMR的介紹到此告一段落,下期我們將介紹與CMPCMR一樣使用Abstract Schema Persistence/Abstract Programming Model來實作的Query LanguageQuery Methods

          參考資料

          1.  Richard Monson-Haefel ---- Enterprise JavaBeans, 3rd Edition, O’Reilly, 2001

          2.  Ueli Wahli, Wouter Denayer, Lars Schunk, Deborah Shaddon, Martin Weiss ---- EJB 2.0 Development with WebSphere Studio Application Developer, 1st Edition, IBM/Redbooks, 2003

          posted on 2008-12-04 11:33 paulwong 閱讀(260) 評論(0)  編輯  收藏 所屬分類: J2EE

          主站蜘蛛池模板: 浙江省| 常德市| 洪江市| 湘潭市| 巴马| 延吉市| 镇雄县| 平山县| 于都县| 孝昌县| 周至县| 普安县| 崇州市| 琼结县| 中江县| 铜鼓县| 原平市| 景谷| 迁西县| 澄江县| 泰和县| 昭苏县| 新化县| 沽源县| 达州市| 林甸县| 丹棱县| 永清县| 湖南省| 湟中县| 上杭县| 营山县| 清涧县| 双江| 呼伦贝尔市| 荣成市| 天柱县| 扶风县| 宜良县| 稻城县| 阳谷县|