複合エンティティパターン
複合エンティティはJava EEソフトウェア設計パターンであり、個々の細粒度のエンティティBeanとして表現するのではなく、相互に関連する永続オブジェクトのセットをモデル化、表現、管理するために使用されます。また、複合エンティティBeanはオブジェクトのグラフを表します。[ 1 ]
構造
複合エンティティパターンを実装する方法はいくつかあります。このパターンは主に、複合エンティティ、粗粒度オブジェクト、および依存オブジェクトを複合化します。[ 1 ]

複合エンティティコンポーネント
複合エンティティは、粗粒度オブジェクトであるか、粗粒度オブジェクトへの参照を含むことができる粗粒度エンティティBeanです。[ 1 ]
粗粒度オブジェクト
粗粒度オブジェクトとは、独自のライフサイクルを持ち、他のオブジェクトとの独自の関係を管理するオブジェクトです。これは複合実体に含まれるオブジェクトである場合もあれば、複合実体自体が依存オブジェクトを保持する粗粒度オブジェクトである場合もあります。[ 1 ]
依存オブジェクト
これは、他の依存オブジェクト(複合エンティティ内にオブジェクトのツリーが存在する場合がある)を含むことができるオブジェクトであり、粗粒度オブジェクトに依存し、そのライフサイクルは粗粒度オブジェクトによって管理されます。[ 1 ]
結果
Oracleによるこのパターンの説明によると、結果として、エンティティ間の関係の排除、エンティティBeanの削減による管理性の向上、ネットワークパフォーマンスの向上、データベーススキーマの依存性の低減、オブジェクトの粒度の向上、複合転送オブジェクトの作成の容易化、および複数レベルの依存オブジェクトグラフのオーバーヘッドの軽減などが挙げられる。[ 1 ]
欠点
致命的な欠点は、Bean管理型永続(BMP)Beanが必要となることです。これにより開発者の作業量が増加し、以下のような問題が生じます。
- アクセスされるたびに、粗粒度のエンティティ内のすべてのデータを具体化することは、許容できないほど高価である。
- Javaでは、すべての永続オブジェクトでデータが変更されていない限り、オブジェクトの状態全体を永続化するために必要なすべての更新を発行しないように、ejbStore() メソッドの実装を十分にスマートにする必要があります。
複合エンティティパターンは、BMPを使用するか、コンテナ管理永続性(CMP) Beanに手動でコーディングされた永続性ロジックを追加することによってのみ実装できます。どちらのアプローチも保守性を低下させます。[ 2 ]
サンプルコード
リソース オブジェクトが複合エンティティ パターンを介して実装されている Professional Service Automation アプリケーション (PSA) のサンプル コードは、次のようになります (エンティティは粗粒度のオブジェクトを実装します)。
パッケージcorepatterns.apps.psa.ejb ;corepatterns.apps.psa.core.*をインポートします。corepatterns.apps.psa.dao .*をインポートします。java.sql .*をインポートします。javax.sql .*をインポートします。java.util .*をインポートします。javax.ejb .*をインポートします。javax.naming .*をインポートします。public class ResourceEntity implements EntityBean { public String employeeId ; public String lastName ; public String firstName ; public String departmentId ; public String practiceGroup ; public String title ; public String grade ; public String email ; public String phone ; public String cell ; public String pager ; public String managerId ; // BlockOutTime 依存オブジェクトのコレクションpublic Collection blockoutTimes ;// SkillSet 依存オブジェクトのコレクションpublic Collection skillSets ;...private EntityContext context ; // エンティティ Bean メソッドの実装public String ejbCreate ( ResourceTO resource ) throws CreateException { try { this . employeeId = resource . employeeId ; setResourceData ( resource ); getResourceDAO (). create ( resource ); } catch ( Exception ex ) { throw new EJBException ( "Reason:" + ...); } return this . employeeId ; } public String ejbFindByPrimaryKey ( String primaryKey ) throws FinderException { boolean result ; try { ResourceDAO resourceDAO = getResourceDAO (); result = resourceDAO . selectByPrimaryKey ( primaryKey ); } catch ( Exception ex ) { throw new EJBException ( "Reason:" + ...); } if ( result ) { return primaryKey ; } else { throw new ObjectNotFoundException (...); } } public void ejbRemove () { try { // 依存オブジェクトを削除するif ( this . skillSets != null ) {SkillSetDAO skillSetDAO = getSkillSetDAO () ; skillSetDAO.setResourceID ( employeeId ) ; skillSetDAO.deleteAll ( ) ; skillSets = null ; } if ( this.blockoutTime ! = null ) { BlockOutTimeDAO blockouttimeDAO = getBlockOutTimeDAO ( ) ; blockouttimeDAO.setResourceID ( employeeId ) ; blockouttimeDAO.deleteAll ( ) ; blockOutTimes = null ; }// 永続ストアからリソースを削除します。ResourceDAO resourceDAO = new ResourceDAO ( employeeId ); resourceDAO . delete (); } catch ( ResourceException ex ) { throw new EJBException ( "Reason:" + ...); } catch ( BlockOutTimeException ex ) { throw new EJBException ( "Reason:" + ...); } catch ( Exception exception ) { ... } } public void setEntityContext ( EntityContext context ) { this . context = context ; } public void unsetEntityContext () { context = null ; } public void ejbActivate () { employeeId = ( String ) context . getPrimaryKey (); } public void ejbPassivate () { employeeId = null ; } public void ejbLoad () { try { // ResourceDAOからリソース情報をロードします。resourceDAO = getResourceDAO (); setResourceData (( ResourceTO ) resourceDAO . load ( employeeId )); // 必要に応じて、他の依存オブジェクトをロードします... } catch ( Exception ex ) { throw new EJBException ( "Reason:" + ...); } } public void ejbStore () { try { // リソース情報を保存getResourceDAO (). update ( getResourceData ());// 必要に応じて依存オブジェクトを保存します... } catch ( SkillSetException ex ) { throw new EJBException ( "Reason:" + ...); } catch ( BlockOutTimeException ex ) { throw new EJBException ( "Reason:" + ...); } ... } public void ejbPostCreate ( ResourceTO resource ) { }// リソース転送オブジェクトを取得するメソッドpublic ResourceTO getResourceTO () { // 新しいリソース転送オブジェクトを作成しますResourceTO resourceTO = new ResourceTO ( employeeId );// すべての値をコピーします。resourceTO.lastName = lastName ; resourceTO.firstName = firstName ; resourceTO.departmentId = departmentId ; ... return resourceTO ; }public void setResourceData ( ResourceTO resourceTO ) { // Transfer Object からエンティティ Bean に値をコピーします。 employeeId = resourceTO . employeeId ; lastName = resourceTO . lastName ; ... }// 依存する転送オブジェクトを取得するメソッドpublic Collection getSkillSetsData () { // skillSets がロードされていない場合は、最初にロードします。// 遅延ロード戦略の実装を参照してください。skillSetsを返します; } ...// 必要に応じて他の get メソッドと set メソッドも使用します...// エンティティ Bean のビジネス メソッドpublic void addBlockOutTimes ( Collection moreBOTs ) throws BlockOutTimeException { // 注: moreBOTs は、// BlockOutTimeTO オブジェクトのコレクションですtry { Iterator moreIter = moreBOTs . iterator (); while ( moreIter . hasNext ()) { BlockOutTimeTO botTO = ( BlockOutTimeTO ) moreIter . next (); if ( ! ( blockOutTimeExists ( botTO ))) { // BlockOutTimeTO をコレクションに追加しますbotTO . setNew (); blockOutTime . add ( botTO ); } else { // BlockOutTimeTO がすでに存在するため、追加できませんthrow new BlockOutTimeException (...); } } } catch ( Exception exception ) { throw new EJBException (...); } }public void addSkillSet ( Collection moreSkills ) throws SkillSetException { // addBlockOutTime() の実装に似ています... }...public void updateBlockOutTime ( Collection updBOTs ) throws BlockOutTimeException { try { Iterator botIter = blockOutTimes.iterator ( ); Iterator updIter = updBOTs.iterator ( ); while ( updIter.hasNext ( )) { BlockOutTimeTO botTO = ( BlockOutTimeTO ) updIter.next (); while ( botIter.hasNext()) { BlockOutTimeTO existingBOT = ( BlockOutTimeTO ) botIter.next ( ) ; //キー値を比較してBlockOutTimeを検索しますif ( existingBOT.equals ( botTO )) { // コレクション内に BlockOutTime が見つかりました// 古い BlockOutTimeTOを新しい BlockOutTimeTO に置き換えますbotTO.setDirty ( ); // 古い依存関係を変更しましたbotTO.resetNew ( ) ; //新しい依存関係ではありませんexistingBOT = botTO ; } } } } catch ( Exception exc ) {新しいEJBExceptionをスローします(...); } }public void updateSkillSet ( Collection updSkills ) throws CommitmentException { // updateBlockOutTime に似ています... ... }...}