Container-managed relationships (CMRs) are a powerful new feature of CMP 2.0. Programmers have been creating relationships between entity objects since EJB 1.0 was introduced (not to mention since the introduction of databases), but before CMP 2.0, a programmer had to write a lot of code for each relationship in order to extract the primary key of the related entity and store it in a pseudo foreign key field. The simplest relationships were tedious to code, and complex relationships with referential integrity required many hours of coding. With CMP 2.0 there is no need to code relationships by hand. The container can manage one-to-one, one-to-many, and many-to-many relationships, with referential integrity. One restriction with CMRs is that they are only defined between local interfaces. This means that a relationship cannot be created between two entities in separate applications, even in the same application server. There are two basic steps to creating a CMR: create the cmr-field abstract accessors and declare the relationship in the ejb-jar.xml file. The following two sections describe these steps. CMR-field Abstract AccessorsCMR-field abstract accessors have the same signatures as cmp-fields, except that singlevalued relationships must return the local interface of the related entity, and multivalued relationships can only return a java.util.Collection (or java.util.Set) object. For example, to declare a one-to-many relationship between the organization and gangster beans, you declare the relationship from organization to gangster in the OrganizationBean class: public abstract class OrganizationBean implements EntityBean { public abstract Set getMemberGangsters(); public abstract void setMemberGangsters(Set gangsters); } You can also declare the relationship from gangster to organization in the GangsterBean class: public abstract class GangsterBean implements EntityBean { public abstract Organization getOrganization(); public abstract void setOrganization(Organization org); } Although each bean declares a CMR field, only one of the two beans in a relationship must have a set of accessors. As with CMP fields, a CMR field is required to have both a getter and a setter method. Relationship DeclarationDeclaring relationships in the ejb-jar.xml file is complicated and error-prone. Although we recommend using a tool such as XDoclet to manage the deployment descriptors for CMR fields, it's still important that you understand how the descriptor works. The following illustrates the declaration of the organization/gangster relationship:
As you can see, each relationship is declared with an ejb-relation element within the top-level relationships element. The relation is given a name in the ejb-relation-name element. This is important because you need to refer to the role by name in the jbosscmp-jdbc.xml file. Each ejb-relation contains two ejb-relationship-role elements (one for each side of the relationship). The ejb-relationship-role tags are as follows:
After you add the CMR field abstract accessors and declare the relationship, the relationship should be functional. The next section discusses the database mapping of the relationship. Relationship MappingYou can map relationships by using either a foreign key or a separate relation table. One-to-one and one-to-many relationships use the foreign key mapping style by default, and many-to-many relationships use only the relation table mapping style. The mapping of a relationship is declared in the relationships section of the jbosscmp-jdbc.xml descriptor via ejb-relation elements. Relationships are identified by the ejb-relation-name from the ejb-jar.xml file. The jbosscmp-jdbc.xml ejb-relation element content model is shown in Figure 11.7. Figure 11.7. The jbosscmp-jdbc.xml ejb-relation element content model.
The basic template of the relationship mapping declaration for the Organization/Gangster relationship follows:
After the ejb-relation-name of the relationship being mapped is declared, you can declare the relationship as read-only by using the read-only and read-time-out elements. They have the same semantics as their counterparts in the entity element. The ejb-relation element must contain either a foreign-key-mapping element or a relation-table-mapping element, which are described in the "Foreign Key Mapping" and "Relation Table Mapping" sections, later in this chapter. This element may also contain a pair of ejb-relationship-role elements, as described in the following section. Relationship Role MappingEach of the two ejb-relationship-role elements contains mapping information that is specific to an entity in the relationship. The content model of the ejb-relationship-role element is shown in Figure 11.8. Figure 11.8. The jbosscmp-jdbc ejb-relationship-role element content model.Detailed descriptions of the main elements follow:
As noted previously, the key-field element contains a key-field element for each primary key field of the current entity. The key-field element uses the same syntax as the cmp-field element of the entity, except that key-field does not support the not-null option. A key field of a relation table is automatically not null because it is the primary key of the table. On the other hand, a foreign key field must be nullable by default. This is because the CMP specification requires an insert into the database after the ejbCreate method and an update to it afterward, to pick up CMR changes made in ejbPostCreate. Because the EJB specification does not allow a relationship to be modified until ejbPostCreate, a foreign key is initially set to null. There is a similar problem with removal. You can change this insert behavior by using the jboss.xml insert-after-ejb-post-create container configuration flag. The following example illustrates the creation of a new bean configuration that uses insert-after-ejb-post-create by default: <jboss> <!-- ... --> <container-configurations> <container-configuration extends="Standard CMP 2.x EntityBean"> <container-name>INSERT after ejbPostCreate Container</container-name> <insert-after-ejb-post-create>true</insert-after-ejb-post-create> </container-configuration> </container-configurations> </jboss> An alternate means of working around the non-null foreign key issue is to map the foreign key elements onto non-null CMP fields. In such a case, you simply populate the foreign key fields in ejbCreate by using the associated CMP field setters. The content model of the key-field element is shown in Figure 11.9. Figure 11.9. The jbosscmp-jdbc key-fields element content model.
Detailed descriptions of the elements contained in the key-field element follow:
Foreign Key MappingForeign key mapping is the most common mapping style for one-to-one and one-to-many relationships, but it is not allowed for many-to-many relationships. You declare the foreign key mapping by adding an empty foreign key-mapping element to the ejb-relation element. As noted in the previous section, with a foreign key mapping, the key-fields elements declared in ejb-relationship-role are added to the table of the related entity. If the key-fields element is empty, a foreign key is not created for the entity. In a one-to-many relationship, the many side (gangster, in the example) must have an empty key-fields element, and the one side (organization, in the example) must have a key-fields mapping. In one-to-one relationships, one or both roles can have foreign keys. The foreign key mapping is not dependent on the direction of the relationship. This means that in a one-to-one unidirectional relationship (only one side has an accessor), one or both roles can still have foreign keys. The complete foreign key mapping for the organization/gangster relationship is shown in the following:
Relation Table MappingRelation table mapping is not very common for one-to-one and one-to-many relationships, but is the only mapping style allowed for many-to-many relationships. Relation table mapping is defined using the relation-table-mapping element, the content model of which is shown in Figure 11.10. Figure 11.10. The jbosscmp-jdbc relation-table-mapping element content model.The relation table mapping for the gangster/job relationship is shown in Listing 11.1. Listing 11.1. The jbosscmp-jdbc.xml Relation Table Mapping<jbosscmp-jdbc> <relationships> <ejb-relation> <ejb-relation-name>Gangster-Jobs</ejb-relation-name> <relation-table-mapping> <table-name>gangster_job</table-name> </relation-table-mapping> <ejb-relationship-role> <ejb-relationship-role-name>gangster-has-jobs</ejb-relationship-role-name> <key-fields> <key-field> <field-name>gangsterId</field-name> <column-name>gangster</column-name> </key-field> </key-fields> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>job-has-gangsters</ejb-relationship-role-name> <key-fields> <key-field> <field-name>name</field-name> <column-name>job</column-name> </key-field> </key-fields> </ejb-relationship-role> </ejb-relation> </relationships> </jbosscmp-jdbc> The relation-table-mapping element contains a subset of the options available in the entity element. Detailed descriptions of these elements follow:
|