Relations Among Entity Beans (EJB 2.02.1)


Relations Among Entity Beans (EJB 2.0/2.1)

Persistent relationships managed by the EJB container (container-managed relationships) among entity beans are one of the important innovations of version 2.0 of the EJB specification. They make possible the mapping of complex data structures through the use of several related entity beans with container-managed persistence.

Relationships are directed; that is, there is a source object and one or more target objects. Unidirectional relationships are relationships in which only one part of the relationship is active. Navigation is then possible in only one direction. Bidirectional relationships are those in which both parties know about the relationship, and navigation can take place in either direction.

Entity beans that stand in relationship to one another must be defined in the same deployment descriptor. Such related entity beans are dependent on one another. Only when they are defined in the same deployment descriptor can the EJB container ensure at run time that the linked entity beans are available.

If the linked entity beans were defined in different deployment descriptors, then they could be installed on different application servers. Thus the EJB container could no longer guarantee the availability of the linked entity beans at run time. The other application server might no longer be operational, or the linked entity beans might have been deinstalled.

Entity beans that belong to the navigable part of a relationship must support the local client view. Otherwise, a reference cannot be made to them via a relationship. Since entity beans that are related must be defined in the same deployment descriptor, at run time they will be found in the same application server process. The use of the local client view ensures optimal performance in navigation across relationships due to the lack of network overhead. Moreover, the management of relationships for the EJB container becomes significantly simpler through use of the local client view and the consequent call-by-reference semantics.

From the point of view of the developer, a relationship between two entity bean types in the sense of this section consists of three components:

The first component consists of the abstract relationship methods in the entity bean class. A relationship to another entity bean receives a name similar to that of a persistent attribute. Depending on the type of relationship (unidirectional or bidirectional) the bean class defines a pair of abstract methods: a method set<relationshipname> and a method get<relationshipname>. The set method serves to create or change a relationship to a particular instance or instances of the other bean type, while the get method supports navigation across the relationship.

The second component is the formal description of the relationship in the deployment descriptor. There it is defined which entity beans stand in relationship to which other beans over which attributes (that is, over which abstract relationship methods) the relationship is established, whether the relationship is unior bidirectional, and the cardinality of the relationship.

The third component is the mapping of the relationships to the persistence medium. In the course of this section we shall assume that a relational database is used as persistence medium. It must be determined how the relationship is to be stored, that is, whether a foreign key or a relation table will be used. Moreover, it must be determined over which entity bean attributes (that is, over which table columns) a relationship is defined. The description of the third component is the task of the deployer, and its form is not set by the specification. Descriptions of the mapping of relationships to the persistence medium differs according to the application server.

In the following sections we will discuss the fundamentals of the various types of relationships.

One-to-One Relationships

Unidirectional

An example of a one-to-one relationship is the relationship between an automobile and the customer who is currently renting that automobile in an application involving an auto rental agency. An automobile can be rented at a particular time to exactly one customer. A customer can use precisely one automobile at a given time. If there is no relationship between a particular automobile and a customer, then that automobile is not currently rented. Figure 5-9 offers a graphical representation of the situation. The figure shows a unidirectional relationship that is stored via a foreign key relationship. The table automobile contains the column customernr (foreign key), which creates the relationship to the particular customer in the table customer.

click to expand
Figure 5-9: Example of a unidirectional one-to-one relationship.

For the case of a unidirectional relationship between an automobile bean and customer bean only the automobile bean defines the abstract relationship methods in the bean class (see Listing 5-16). The data type of the relationship is always the type of the local interface of the related entity bean.

Listing 5-16: Abstract relationship methods for an automobile bean.

start example
 ...     //Persistent attributes     public abstract void setIDnumber(String id);     public abstract String getIDnumber();     //Persistent Relationshps     public abstract void setCustomer(CustomerLocal customer);     public abstract CustomerLocal getCustomer(); ... 
end example

The direction of the relationship is from the automobile bean to the customer bean. Therefore, the customer bean must support the local client view, since it is reachable by the automobile bean using navigation. The automobile bean need not support the local client view in the case of a unidirectional relationship, since it is not reachable by navigation across the relationship. If there is no relationship to the customer bean, then a call to the method getCustomer returns the value null.

Listing 5-17 shows the formal description of the relationship in the deployment descriptor. The element ejb-relation involves the element ejb-relationship-name and always two elements ejb-relationship-role, one for each side of the relationship. Each side of the relationship receives a name via the element ejb-relationship-role-name. This name will have later meaning for the mapping to the database. For each part of the relationship the cardinality is given via the element multiplicity. The entity bean that will take part in the relationship is specified via relationship-role-source. The element cmr-field names the attribute of the bean over which the relationship is to be stored. If this field is missing on one of the two sides of the relationship, then we are automatically dealing with a unidirectional relationship; the direction depends on which side the element cmr-field is defined. The automobile bean has defined the methods setCustomer and getCustomer for the storage and navigation of the relationship. Thus the value for the element must be cmr-field-name customer, since otherwise, the EJB container would not be able to create the assignment to the relationship methods.

Listing 5-17: Formal description of the relationship Automobile-Customer (unidirectional).

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>Automobile</ejb-name>       ...     </entity>     <entity>       <ejb-name>Customer</ejb-name>       <local-home>CustomerLocalHome</local-home>       <local>CustomerLocal</local>       ...     </entity>     ...   </enterprise-beans> ...   <ejb-relation>     <ejb-relation-name>Automobile-Customer</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         automobile-has-customer       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>Automobile</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>customer</cmr-field-name>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         cutomer-uses-automoble       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>Customer</ejb-name>       </relationship-role-source>     </ejb-relationship-role>   </ejb-relation> ... 
end example

The missing component is the description for how the relationship is to be mapped to the database. As we have already mentioned, its form is not determined by the specification. Every application server has its own format of how this mapping to the persistence medium is to be described. Listing 5-18 shows an imaginary example for the sake of clarifying the principle of this association.

Listing 5-18: Mapping of the Automobile-Customer relationship to the database.

start example
 <bean-mapping>   <ejb-name>Automobile</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>automobile</table-name>   <field-map>     <cmp-field>IDnumber</cmp-field>     <dbms-column>IDnumber</dbms-column>   </field-map> </bean-mapping> <bean-mapping>   <ejb-name>Customer</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>customer</table-name>   <field-map>     <cmp-field>customernr</cmp-field>     <dbms-column>customernr</dbms-column>   </field-map>   <field-map>     <cmp-field>name</cmp-field>     <dbms-column>name</dbms-column>   </field-map> </bean-mapping> ... <relation-mapping>   <relation-name>Automible-Customer</relation-name>     <relationship-role>       <relationship-role-name>         automobile-has-customer       </relationship-role-name>       <column-map>         <foreign-key-column>customernr</foreign-key-column>         <key-column>customernr</key-column>       </column-map>     </relationship-role> </relation-mapping> 
end example

First the mapping of the entity beans Automobile and Customer to the database is described (bean-mapping). Then the mapping of the relationship is described. The EJB container knows from the deployment descriptor that the automobile and customer beans are participating in a relationship. Furthermore, it knows that it is dealing with a one-to-one relationship and that the relationship is unidirectional (from the automobile bean to the customer bean). From the description of the relationship (relation-mapping) it now also knows that the foreign key is stored in the table of the automobile bean. It is the part of the relationship with the name automobile-has-customer (whose relationship-role-source the automobile bean is) that is described and not the part customer-uses-automobile. The EJB container then maps the relationship via the column customernr of the table automobile (foreign key) to the column customernr of the table customer. With this information the tools of the EJB container and those of the persistence manager are able to generate the necessary code for managing the relationship and to handle the relationship correctly at run time.

Bidirectional

In order to extend the unidirectional relationship depicted in Figure 5-9 to a bidirectional relationship, the automobile bean must now support the local client view. Otherwise, it cannot be referred to by the customer bean. Like the automobile bean, the customer bean must define abstract relationship methods (see Listing 5-19).

Listing 5-19: Abstract relationship methods of the customer bean.

start example
 ...     //Persistent attributes     public abstract void setCustomernr(String kn);     public abstract String getCustomenr();     public abstract void setName(String name);     public abstract String getName();     //Persistent relationships     public abstract void setAutomobile(AutomobileLocal fl);     public abstract AutomobileLocal getAutomobile(); ... 
end example

If a relationship between the automobile and customer beans is created via the method setCustomer on the side of the automobile bean, then the relationship is also immediately visible by the customer bean. The same holds in the opposite direction. If a relationship is created between automobile and customer beans by a call to the method setAutomobile, then the relationship is also at once visible to the automobile bean. In the case of a bidirectional relationship it thus suffices to create the relationship on one of the two sides. It is then automatically navigable from the other side. If there is no relationship between two Enterprise Beans that are linked with cardinality one-to-one, then a call to the relevant getter methods returns the value null.

The bidirectionality of the relationship is declared in the deployment descriptor by the fact that now the element cmr-field is declared for both sides of the relationship (see Listing 5-20). Finally, the declaration in the deployment descriptor is the crucial factor for the relationship to be navigable in both directions.

Listing 5-20: Formal description of the relationship Automobile-Customer (bidirectional).

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>Automobile</ejb-name>       <local-home>AutomobileLocalHome</local-home>       <local>AutomobileLocal</local>       ...     </entity>     <entity>       <ejb-name>Customer</ejb-name>       <local-home>CustomerLocalHome</local-home>       <local>CustomerLocal</local>       ...     </entity>     ...   </enterprise-beans> ...   <ejb-relation>     <ejb-relation-name>Automobile-Customer</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         automobile-has-customer       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>Automobile</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>customer</cmr-field-name>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         customer-uses-automobile       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>Customer</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>automobile</cmr-field-name>       </cmr-field>     </ejb-relationship-role>   </ejb-relation> ... 
end example

The description of the mapping to the database does not have to be changed. The EJB container already knows how the relationship is to be stored. The foreign key relation illustrated in Figure 5-9 enables navigation in both directions. It matters little for the programming whether the relationship is unior bidirectional. For the EJB container the navigation in one direction or the other of the relationship is merely a reflection of a database query.

One-to-n Relationships (One to Many)

Unidirectional Relationships

An example of a one-to-n relationship is the relationship between a department and its employees, as depicted in Figure 5-10. A number of employees work in one department. An employee is always associated with precisely one department (if an employee could be associated with several departments, then we would no longer be dealing with a a one-to-n relationship). In this case as well, the relationship is stored using a foreign key relation between the relevant tables. The table employee contains the column accountingnr (= foreign key), which creates the department in the table department. Alternatively, one could use a relation table. The use of a relation table will be discussed in the next section.

click to expand
Figure 5-10: Example of a unidirectional one-to-n relationship.

For the case of a unidirectional relationship between the department and employee beans only the department bean implements the abstract relationship methods in the bean class (see Listing 5-21). Since the department bean can have a relationship to several employee beans, the data type of the relationship is of type java.util.Collection or java.util.Set.

Listing 5-21: Abstract relationship methods of the department bean.

start example
 ...     //Persistent attributes     public abstract void setAccountingnr(String knr);     public abstract String getAccountingnr();     //Persistent relationships     public abstract void setEmployee(Collection ma);     public abstract Collection getEmployee(); ... 
end example

The difference between java.util.Collection and java.util.Set is that a Collection is allowed to contain duplicate members, while a Set cannot. In our example is doesn't matter which class is used. An employee can in any case be associated with only one department. The accounting number of the employee in unique, since it is the primary key in the table. Therefore, the database ensures that there are no duplicates.

The employee bean must support the local client view, since it can then be referenced through navigation by the department bean. The department bean need not support the local client view, since the relationship is unidirectional, pointing from the department bean to the employee bean.

The description of the relationship in the deployment descriptor is distinguished from one-to-one relationships only in the cardinality (Listing 5-22). Furthermore, it must be specified by the element cmr-field-type whether java.util.Collection or java.util.Set will be used as the data container.

Listing 5-22: Formal description of the relationship DepartmentEmployee (unidirectional).

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>Department</ejb-name>       ...     </entity>     <entity>       <ejb-name>Employee</ejb-name>       <local-home>EmployeeLocalHome</local-home>       <local>EmployeeLocal</local>       ...     </entity>     ...   </enterprise-beans> ...   <ejb-relation>    <ejb-relation-name>Department-Employee</ejb-relation-name>    <ejb-relationship-role>      <ejb-relationship-role-name>        department-has-employee      </ejb-relationship-role-name>      <multiplicity>One</multiplicity>      <relationship-role-source>        <ejb-name>Department</ejb-name>      </relationship-role-source>      <cmr-field>        <cmr-field-name>employee</cmr-field-name>        <cmr-field-type>java.util.Collection</cmr-field-type>      </cmr-field>    </ejb-relationship-role>    <ejb-relationship-role>      <ejb-relationship-role-name>         employee-is-in-department       </ejb-relationship-role-name>       <multiplicity>Many </multiplicity>       <relationship-role-source>         <ejb-name>Employee</ejb-name>       </relationship-role-source>     </ejb-relationship-role>   </ejb-relation> ... 
end example

The description of the mapping to the database (see Listing 5-23) is just about the same as that of one-to-one relationships. But be careful in describing the foreign key relation: One must describe the foreign key relation for the correct side of the relationship. In this case we are dealing with the side employee-is-in-department, since the relationship-role-source is the employee bean. It is mapped to the table employee, which contains the foreign key.

Listing 5-23: Mapping of the Department-Employee relationship to the database.

start example
 <bean-mapping>   <ejb-name>Department</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>department</table-name>   <field-map>     <cmp-field>accountingnr</cmp-field>     <dbms-column>accountingnr</dbms-column>   </field-map> </bean-mapping> <bean-mapping>   <ejb-name>Employee</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>employee</table-name>   <field-map>     <cmp-field>personnelnr</cmp-field>     <dbms-column>personnelnr</dbms-column>   </field-map> </bean-mapping> ... <relation-mapping>   <relation-name>Department-Employee</relation-name>     <relationship-role>       <relationship-role-name>         employee-is-in-department       </relationship-role-name>       <column-map>         <foreign-key-column>accountingnr</foreign-key-column>         <key-column>accountingnr</key-column>       </column-map>     </relationship-role> </relation-mapping> 
end example

A feature of note for the bean developer in the use of a one-to-n relationship is the use of the cardinality n of the relationship, which is represented by the data type java.util.Collection or java.util.Set.

In contrast cardinality 1, the get method with the cardinality n never returns the value null. If no relationship exists between the bean instances, then the return value is a Collection or Set object containing no elements (thus is empty).

To set up relationships between the department and employee beans, the bean developer has two options: The variant shown in Listing 5-24 uses the method setEmployee of the department bean. It creates a relationship to employees A, B, and C. If the department bean already had a relationship to employees D and E, then that relationship would be deleted. The semantics of a set method are to overwrite existing values. This is also the case with relationships. The relationship to employees D and E would be overwritten by the relationship to A, B, and C. The relationship to employees D and E would no longer exist.

Listing 5-24: Setting relationships using the method setEmployee().

start example
 ... EmployeeLocalHome employeeHome = ... DepartmentHome departmentHome = ... Department department = departmentHome.findByPrimaryKey(...); EmployeeLocal mA = employeeHome.create("A", ...); EmployeeLocal mB = employeeHome.create("B", ...); EmployeeLocal mC = employeeHome.create("C", ...); java.util.ArrayList al = new java.util.ArrayList(); al.add(mA); al.add(mB); al.add(mC); department.setEmployee(al); ... 
end example

Listing 5-25 shows how relationships to employees can be set up without overwriting existing relationships.

Listing 5-25: Adding relationships using the method Collection.add().

start example
 ... EmployeeLocalHome employeeHome = ... DepartmentHome departmentHome = ... Department department = departmentHome.findByPrimaryKey(...); java.util.Collection col = department.getEmployee(); EmployeeLocal mA = employeeHome.create("A", ...); EmployeeLocal mB = employeeHome.create("B", ...); EmployeeLocal mC = employeeHome.create("C", ...); col.add(mA); col.add(mB); col.add(mC); ... 
end example

The object that the method getEmployee of the department bean returns is an implementation of the interface java.util.Collection, which is supplied by the EJB container. With the Collection object the EJB container grants the bean developer access to the cardinality n of the relationship with the employee bean. Method calls on this Collection object are processed by the EJB container. Changes are relayed immediately to the database by the EJB container.

The bean developer must note that an employee bean can be linked to only one department bean. If employee H is in department B, then adding employee H to department C would have the effect of deleting the link to department B. This behavior is determined by the fact that the relationship has cardinality 1-to-n. If an employee can be related to two or more departments, then we are dealing with a cardinality of n-to-m.

Listing 5-26 shows how the bean developer can navigate over a relationship of cardinality n to a particular bean.

Listing 5-26: Navigation over the cardinality n to the department bean.

start example
 ... java.util.Collection col = department.getEmployee(); java.util.Iterator it = col.iterator(); while(it.hasNext()) {     EmployeeLocal ma = (EmployeeLocal)it.next();     if(ma.getName().equals(nameToSearchFor)) {        ...     }     ... } ... 
end example

The objects contained within the collection are always of the type of the local interface of the linked bean. Therefore, it is unnecessary to employ type narrowing via the method narrow of the class javax.rmi.PortableRemoteObject.

Listing 5-27 shows how the bean developer can delete a relationship to a bean of cardinality n.

Listing 5-27: Deleting a relationship to the department bean of cardinality n.

start example
 ... java.util.Collection col = department.getEmployee(); java.util.Iterator it = col.iterator(); while(it.hasNext()) {     EmployeeLocal ma = (EmployeeLocal)it.next();     if(ma.isFired()) {         it.remove();     } } ... 
end example

The deletion of a relationship does not, of course, mean the deletion of the linked bean instance. Only the relationship between the two entity beans is deleted. The EJB container sets the value of the foreign key column to null.

Bidirectional Relationships

To transform a unidirectional one-to-n relationship into a bidirectional one-to-n requires the same steps as in the case of a one-to-one relationship. The department bean must also support the local client view, since otherwise, it cannot be referenced by the employee bean. Moreover, the employee bean must define abstract relationship methods (see Listing 5-28). Since the cardinality is declared to be 1 from the department bean side of things, the relationship methods are of type DepartmentLocal.

Listing 5-28: Abstract relationship methods of the employee bean.

start example
 ...     //Persistent attributes     public abstract void setPersonnelnumber(String pn);     public abstract String getPersonnelnumber();     //Persistent relationships     public abstract void setDepartment(DepartmentLocal al);     public abstract DepartmentLocal getDepartment(); ... 
end example

The abstract relationship methods of the employee bean must still be declared in the deployment descriptor (see Listing 5-29). It is only the declaration of the relationship methods in the deployment descriptor that makes the relationship bidirectional.

Listing 5-29: Formal description of the relationship Department-Employee (bidirectional).

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>Department</ejb-name>       <local-home>DepartmentLocalHome</local-home>       <local>DepartmentLocal</local>       ...     </entity>     <entity>       <ejb-name>Employee</ejb-name>       <local-home>EmployeeLocalHome</local-home>       <local>EmployeeLocal</local>       ...     </entity>     ...   </enterprise-beans> ...   <ejb-relation>     <ejb-relation-name>Department-Employee</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         department-has-employee       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>Department</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>employee</cmr-field-name>         <cmr-field-type>java.util.Collection</cmr-field-type>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         employee-is-in-department       </ejb-relationship-role-name>       <multiplicity>Many</multiplicity>       <relationship-role-source>         <ejb-name>Employee</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>department</cmr-field-name>       </cmr-field>     </ejb-relationship-role>   </ejb-relation> ... 
end example

The description of the mapping to the database is (as with one-to-one relationships) identical to the unidirectional one-to-n relationship. At the database level the relationship is already navigable. Navigation in the other direction is merely the mirror-image formulation of a database query.

n-to-m Relationships (Many to Many)

Unidirectional Relationships

An example of an n-to-m relationship is that between a product and a product part. Figure 5-11 clarifies the situation. A product part can be used with several products. However, in this case, for storing the relationship a foreign key relation can no longer be used. A necessary condition for being able to use a foreign key relation is that uniqueness exist in at least one direction of the relationship. In the case of n-to-m relationships that is no longer the case. Therefore, for storing the relationship a relation table is used. It exists only for the purpose of storing relationships. It contains all fields of the primary key of the entities that are involved.

click to expand
Figure 5-11: Example of a unidirectional n-to-m relationship.

For the case of unidirectional n-to-m relationships only the product bean defines the abstract relationship methods in the bean class (see Listing 5-30). Since the product bean relationships can have several product part beans, the abstract relation methods are of type java.util.Collection and java.util.Set.

Listing 5-30: Abstract relationship methods of the product bean.

start example
 ...     //Persistent attributes     public abstract void setProductId(String pid);     public abstract String getProductId();     //Persistent relationships     public abstract void setOptionalpart(Collection zt);     public abstract Collection getOptionalpart(); ... 
end example

The differences between java.util.Collection and java.util.Set and their uses in setting up, adding, and deleting relationships was handled in the previous section. However, there exists a noteworthy difference in comparison with the one-to-n relationships that is based on the semantics of the n-to-m relationships.

For example, if product A has a relationship to product part X, and now product part X is placed in relationship to product D, then this has no effect on the relationship to product A. Both products, A and D, have a relationship to product part X. In a one-to-n relationship the relationship to product A would have been deleted by the relationship to product D.

Listing 5-31 shows the description of the unidirectional n-to-m relationship between the product bean and product part bean in the deployment descriptor. The product part bean must support the local client view, since it is referred to by the product bean via navigation. In the case of a unidirectional relationship the product bean need not support the local client view.

Listing 5-31: Formal description of the relationship Product-Optionalpart (unidirectional).

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>Product</ejb-name>       ...     </entity>     <entity>       <ejb-name>Optionalpart</ejb-name>       <local-home>OptionalpartLocalHome</local-home>       <local>OptionalpartLocal</local>       ...     </entity>     ...   </enterprise-beans>   ...   <ejb-relation>     <ejb-relation-name>Product-Optionalpart</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         product-has-optionalpart       </ejb-relationship-role-name>       <multiplicity>Many</multiplicity>       <relationship-role-source>         <ejb-name>Product</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>optionalpart</cmr-field-name>         <cmr-field-type>java.util.Collection</cmr-field-type>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         optionalpart-is-in-product       </ejb-relationship-role-name>       <multiplicity>Many</multiplicity>       <relationship-role-source>         <ejb-name>Optionalpart</ejb-name>       </relationship-role-source>     </ejb-relationship-role>   </ejb-relation> ... 
end example

Listing 5-32 shows an imaginary example of how the mapping of the relation to the database can be described. What is new in comparison to the previous examples is the necessity of using a relation table.

Listing 5-32: Mapping of the Product-Optionalpart relationship to the database.

start example
 <bean-mapping>   <ejb-name>Product</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>product</table-name>   <field-map>     <cmp-field>productId</cmp-field>     <dbms-column>productid</dbms-column>   </field-map> </bean-mapping> <bean-mapping>   <ejb-name>Optionalpart</ejb-name>   <data-source-name>postgres</data-source-name>   <table-name>optionalpart</table-name>   <field-map>     <cmp-field>partNumber</cmp-field>     <dbms-column>partnr</dbms-column>   </field-map> </bean-mapping> ... <relation-mapping>   <relation-name>Product-Optionalpart</relation-name>   <relation-table>productlink</relation-table>     <relationship-role>       <relationship-role-name>         product-has-optionalpart       </relationship-role-name>       <column-map>         <foreign-key-column>productid</foreign-key-column>         <key-column>productid</key-column>       </column-map>     </relationship-role>     <relationship-role>       <relationship-role-name>         optionalpart-is-in-product       </relationship-role-name>       <column-map>         <foreign-key-column>partnr</foreign-key-column>         <key-column>partnr</key-column>       </column-map>     </relationship-role> </relation-mapping> 
end example

First the mapping of the persistent attributes of the entity beans is described in the relevant tables. The description of the relationship specifies that a relation table is being used and gives its name. Then the mapping must be described for both sides of the relationship in the relation table. The description for only one side of the relationship, as with the use of a foreign key, is insufficient, since both sides of the relationship have a foreign key relationship to the relation table.

Bidirectional Relationships

As was the case for one-to-one and one-to-n relationships, the extension of a unidirectional n-to-m relationship to a bidirectional n-to-m relationship is relatively easy. The product bean must also support the local client view, so that it can be referenced by the product part bean. The product part bean must declare abstract relationship methods (see Listing 5-33) to enable navigation in the opposite direction (from the product part bean to the product bean). Since a product part bean can be related to several products, the relationship is of type java.util.Collection (or java.util.Set).

Listing 5-33: Abstract relationship methods of the product part bean.

start example
 ...     //Persistent attributes     public abstract void setPartNumber(String tn);     public abstract String getPartNumber();     //Persistent relationships     public abstract void setProduct(Collection p);     public abstract Collection getProduct(); ... 
end example

The next building block for the extension into a bidirectional n-to-m relationship is the declaration of the abstract relationship methods in the product part bean in the deployment descriptor (see Listing 5-34).

Listing 5-34: Formal description of the relationship Product-Optionalpart (bidirectional).

start example
   <enterprise-beans>     <entity>       <ejb-name>Product</ejb-name>       <local-home>ProductLocalHome</local-home>       <local>ProductLocal</local>       ...     </entity>     <entity>       <ejb-name>OptionalPart</ejb-name>       <local-home>OptionalpartLocalHome</local-home>       <local>OptionalpartLocal</local>       ...     </entity>     ...   </enterprise-beans>   ...   <ejb-relation>     <ejb-relation-name>product-optionalpart</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         product-has-optionalpart       </ejb-relationship-role-name>       <multiplicity>Many</multiplicity>       <relationship-role-source>         <ejb-name>Product</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>optionalpart</cmr-field-name>         <cmr-field-type>java.util.Collection</cmr-field-type>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         optionalpart-is-in-product       </ejb-relationship-role-name>       <multiplicity>Many</multiplicity>       <relationship-role-source>         <ejb-name>Optionalpart</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>product</cmr-field-name>         <cmr-field-type>java.util.Collection</cmr-field-type>       </cmr-field>     </ejb-relationship-role>   </ejb-relation> ... 
end example

The description of the mapping to the database is (as with the other types of relationships) identical to the unidirectional n-to-m relationship. The use of a relation table enables navigation in both directions.

Cascading Delete

When a relationship between entity beans is deleted, the entity beans themselves remain untouched. That is, only the relationship between the entity beans is deleted, not the entity beans themselves. However, in many cases the relationship between two entity beans is such that the existence of the beans without the relationship makes little sense. An example of this is a bidirectional one-to-one relationship between the entity bean User and the entity bean Userprofile. The entity bean User stores data such as user name, encrypted password, or the user's access privileges. These data are a precondition for the user being able to operate within the system. The entity bean Userprofile stores data such as the full name of the user, the department in which he or she works, and a telephone number. These data constitute additional information that might be used, say, for analysis. If the user bean of a particular user is deleted (for example, if the employee leaves the company), the relationship to the user profile bean is also deleted by the EJB container. The user profile bean of this user is now a floating cadaver within the system if it has not been explicitly deleted. Without the user, the user profile can no longer be referenced.

For such cases one can notify the EJB container that when the entity bean is deleted, all entity beans related to it are to be deleted as well. This mechanism is called cascading delete. Listing 5-35 shows how one can notify the EJB container to execute a cascading delete.

Listing 5-35: Declaration of a cascading delete.

start example
 ...   <enterprise-beans>     <entity>       <ejb-name>User</ejb-name>       ...     </entity>     <entity>       <ejb-name>Userprofile</ejb-name>       ...     </entity>     ...   </enterprise-beans>   ...   <ejb-relation>     <ejb-relation-name>User-Userprofile</ejb-relation-name>     <ejb-relationship-role>       <ejb-relationship-role-name>         user-has-userprofile       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <relationship-role-source>         <ejb-name>User</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>profil</cmr-field-name>       </cmr-field>     </ejb-relationship-role>     <ejb-relationship-role>       <ejb-relationship-role-name>         userprofile-belongs-to-user       </ejb-relationship-role-name>       <multiplicity>One</multiplicity>       <cascade-delete/>       <relationship-role-source>         <ejb-name>Userprofile</ejb-name>       </relationship-role-source>       <cmr-field>         <cmr-field-name>user</cmr-field-name>       </cmr-field>     </ejb-relationship-role>   </ejb-relation> ... 
end example

If a particular user bean is deleted, then the (XML) element cascade-delete in Listing 5-35 has the effect that the linked user profile bean will automatically be deleted along with it by the EJB container. Cascading delete can proceed only from an entity bean whose cardinality is one. Otherwise, one could not be sure that the deleted entity bean didn't still have other relationships, and that could jeopardize the consistency of the stored data.

The instruction cascade-delete is a powerful tool, and it should be used with care. The user profile bean could, for example, have a relationship to another bean in which a cascade-delete is declared, which could have a relationship to another bean in which a cascade-delete is declared, which could, well, you get the idea. That is, cascading deletion of one entity bean could result in a virtual chain reaction being set off. In complex applications with many relationships it can be difficult to keep track of all the dependencies, which is necessary in using cascade-delete correctly.

To conclude this section on relationships among entity beans we would like to call the reader's attention to the explanations of relationships between entity beans in Sections 10.3.6 and 10.3.7 of the EJB specification (see [21]).




Enterprise JavaBeans 2.1
Enterprise JavaBeans 2.1
ISBN: 1590590880
EAN: 2147483647
Year: 2006
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net