Container-Managed Relationships


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 Accessors

CMR-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 Declaration

Declaring 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:

[View full width]

<ejb-jar> <relationships> <ejb-relation> <ejb-relation-name>Organization-Gangster</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>org-has-gangsters</ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>OrganizationEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>memberGangsters</cmr-field-name> <cmr-field-type>java.util.Set</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>gangster-belongs-to-org< /ejb-relationship-role-name> <multiplicity>Many</multiplicity> <cascade-delete/> <relationship-role-source> <ejb-name>GangsterEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>organization</cmr-field-name> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

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:

  • ejb-relationshiprole-name This optional element is used to identify the specific role externally (for example, the jbosscmp-jdbc.xml file). The relationship role names for both sides of a relationship must be different.

  • multiplicity This indicates the multiplicity of this side of the relationship. The valid values are One and Many. In this example, the multiplicity of organization is One and the multiplicity of gangster is Many because the relationship is from one organization to many gangsters. Note that, as with all XML elements, this element is case-sensitive.

  • cascade-delete When this optional element is present, JBoss deletes the child entity when the parent entity is deleted. Cascade deletion is allowed only for a role where the other side of the relationship has a multiplicity of one. The default is to not cascade delete.

  • relationship-role-source This element contains the following element:

    • ejb-name This required element gives the name of the entity that has the role.

  • cmr-field This element contains the following elements:

    • cmr-field-name This is the name of the CMR field of the entity, if it has one.

    • cmr-field-type This is the type of the CMR field, if the field is a collection type. It must be java.util.Collection orjava.util.Set.

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 Mapping

You 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:

[View full width]

<jbosscmp-jdbc> <relationships> <ejb-relation> <ejb-relation-name>Organization-Gangster</ejb-relation-name> <foreign-key-mapping/> <ejb-relationship-role> <ejb-relationship-role-name>org-has-gangsters</ejb-relationship-role-name> <key-fields> <key-field> <field-name>name</field-name> <column-name>organization</column-name> </key-field> </key-fields> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>gangster-belongs-to-org< /ejb-relationship-role-name> <key-fields/> </ejb-relationship-role> </ejb-relation> </relationships> </jbosscmp-jdbc>

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 Mapping

Each 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:

  • ejb-relationship-role-name This required element gives the name of the role to which this configuration applies. It must match the name of one of the roles declared for this relationship in the ejb-jar.xml file.

  • fk-constraint This optional element is a true/false value that indicates whether JBoss should add a foreign key constraint to the tables for this side of the relationship. JBoss will generate the constraint only if both the primary table and the related table were created by JBoss during deployment.

  • key-fields This optional element specifies the mapping of the primary key fields of the current entity, whether it is mapped in the relation table or in the related object. The key-fields element must contain a key-field element for each primary key field of the current entity. The key-fields element can be empty if no foreign key mapping is needed for this side of the relation. An example of this would be the many side of a one-to-many relationship.

  • read-ahead This optional element controls the caching of this relationship.

  • batch-cascade-delete This indicates that a cascade delete on this relationship should be performed with a single SQL statement. This requires that the relationship be marked as batch-delete in the ejb-jar.xml file.

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:

  • field-name This required element identifies the field to which this mapping applies. This name must match a primary key field of the current entity.

  • column-name You use this element to specify the column name in which this primary key field will be stored. If this relationship uses foreign-key-mapping, this column will be added to the table for the related entity. If this relationship uses relation-table-mapping, this column is added to the relation-table. This element is not allowed for mapped DVCs; instead, you use the property element.

  • jdbc-type This is the JDBC type that is used when setting parameters in a JDBC PreparedStatement or loading data from a JDBC ResultSet. The valid types are defined in java.sql.Types.

  • sql-type This is the SQL type that is used in create table statements for this field. Valid types are limited only by your database vendor.

  • property You use this element to specify the mapping of a primary key field that is a dependent value class.

  • dbindex The presence of this optional field indicates that the server should create an index on the corresponding column in the database, and the index name will be fieldname_index.

Foreign Key Mapping

Foreign 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:

[View full width]

<jbosscmp-jdbc> <relationships> <ejb-relation> <ejb-relation-name>Organization-Gangster</ejb-relation-name> <foreign-key-mapping/> <ejb-relationship-role> <ejb-relationship-role-name>org-has-gangsters</ejb-relationship-role-name> <key-fields> <key-field> <field-name>name</field-name> <column-name>organization</column-name> </key-field> </key-fields> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>gangster-belongs-to-org< /ejb-relationship-role-name> <key-fields/> </ejb-relationship-role> </ejb-relation> </relationships> </jbosscmp-jdbc>

Relation Table Mapping

Relation 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:

  • table-name This optional element gives the name of the table that will hold data for this relationship. The default table name is based on the entity and cmr-field names.

  • datasource This optional element gives the jndi-name used to look up the datasource. All database connections are obtained from the datasource. Having different datasources for entities is not recommended because it vastly constrains the domain over which finders and ejbSelects can query.

  • datasourcemapping This optional element allows you to specify the name of the type-mapping to use.

  • create-table This optional element, if true, indicates that JBoss should attempt to create a table for the relationship. When the application is deployed, JBoss checks whether a table already exists before creating the table. If a table is found, it is logged, and the table is not created. This option is very useful during the early stages of development, when the table structure changes often.

  • post-table-create This optional element specifies an arbitrary SQL statement that should be executed immediately after the database table is created. This command is executed only if create-table is true and the table did not previously exist.

  • remove-table This optional element, if true, indicates that JBoss should attempt to drop the relation-table when the application is undeployed. This option is very useful during the early stages of development, when the table structure changes often.

  • row-locking This optional element, if true, indicates that JBoss should lock all rows loaded in a transaction. Most databases implement this by using the SELECT FOR UPDATE syntax when loading the entity, but the actual syntax is determined by row-locking-template in the datasource-mapping used by this entity.

  • pk-constraint This optional element, if true, indicates that JBoss should add a primary key constraint when creating tables.



JBoss 4. 0(c) The Official Guide
JBoss 4.0 - The Official Guide
ISBN: B003D7JU58
EAN: N/A
Year: 2006
Pages: 137

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