Oracle® Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 2 (10.1.2) Part No. B15505-01 |
|
![]() Previous |
![]() Next |
In the EJB specification, the primary key for an entity bean must be initialized within the ejbCreate
method; any relationship that this bean has to another bean cannot be set in the ejbCreate
method. The earliest that this relationship can be set in a foreign key is in the ejbPostCreate
method.
However, if you have a foreign key within a composite primary key, you have the following problem:
You must set all fields within the composite primary key in the ejbCreate
method.
You cannot set the foreign key in the ejbCreate
method.
This section uses the following example to describe the way around this problem:
An order for a company can contain one or more items. The order bean has many items in it. Each item belongs to an order. The primary key for the item is a composite primary key consisting of the item identifier and the order identifier. The order identifier is a foreign key that points to the order.
You will have to modify the deployment descriptors and bean implementation to add a placeholder CMP field that mimics the actual foreign key field. This field is set during the ejbCreate
method. However, both the placeholder CMP field and the foreign key point to the same database column. The actual foreign key is updated during the ejbPostCreate
method.
The following example demonstrates how to modify both deployment descriptors and the bean implementation.
Example 6-11 A Foreign Key That Exists in a Primary Key
Each order contains one or more items. Thus, two beans are created, where the OrderBean
represents the order and the OrderItemBean
represents the items in the order. Each item has a primary key that consists of the item number and the order number to which it belongs. Thus, the primary key for the item contains a foreign key that points to an order bean.
To adjust for a composite primary key, do the following in the ejb-jar.xml
file:
Define a CMP field in the primary key as a placeholder for the foreign key. This placeholder should be used in the composite primary key class definition.
In this example, an orderId
CMP field is defined in a <cmp-field>
element. The orderId
and itemId
CMP fields are used to identify the composite primary key in the OrderItemPK.java
.
Define the foreign key outside of the primary key definition in its own <cmr-field>
element in the <relationships>
section.
In this example, the belongToOrder
foreign key is defined in a <cmr-field>
element for the OrderItemBean
, defining the relationship from the item to the order.
<entity> <ejb-name>OrderItemBean</ejb-name> <local-home>OrderItemLocalHome</local-home> <local>OrderItemLocal</local> <ejb-class>OrderItemBean</ejb-class> ... <cmp-field><field-name>itemId</field-name></cmp-field> <cmp-field><field-name>orderId</field-name></cmp-field> <cmp-field><field-name>price</field-name></cmp-field> <prim-key-class>OrderItemPK</prim-key-class> ... </entity> <relationships> <ejb-relation> <ejb-relation-name>Order-OrderItem</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>Order-Has-OrderItems </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>OrderBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>items</cmr-field-name> <cmr-field-type>java.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>OrderItems-form-Order </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <cascade-delete/> <relationship-role-source> <ejb-name>OrderItemBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>belongToOrder</cmr-field-name> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships>
The OrderItemPK.java
class defines what is in the complex primary key, as follows:
public class OrderItemPK implements java.io.Serializable { public Integer itemId; public Integer orderId; public OrderItemPK() { this.itemId = null; this.orderId = null; } public OrderItemPK(Integer itemId, Integer orderId) { this.itemId = itemId; this.orderId = orderId; } } public boolean equals(Object o) { if (o instanceof OrderItemPK) { OrderItemPK pk = (OrderItemPK) o; if (pk.itemId.intValue() == itemId.intValue() && pk.orderId.intValue() == orderId.intValue()) return true; } return false; } public int hashCode() { return itemId.hashCode() * orderId.hashCode(); } }
If the auto-created database tables are sufficient for you, you do not need to modify the orion-ejb-jar.xml
file. However, if you need to map to existing database tables, then you modify the orion-ejb-jar.xml
file to point to these tables.
After you allow the orion-ejb-jar.xml
file to auto-generate, copy it into your development directory. The database column names are defined in the persistence-name
attributes in each of the CMP and CMR field name mappings. Ensure that the persistence-name
attributes for both the placeholder CMP field and foreign key are the same.
The following is the orion-ejb-jar.xml
file for the order/order item example. In the <entity-deployment>
section for the OrderItemBean
,
The table is defined in the table
attribute, which is ORDER_ITEM
in this example.
The column name for the itemId
is defined in the persistence-name
attribute as Item_ID
.
The column name for the placeholder CMP field, orderId
, is defined in the persistence-name
attribute as Order_ID
.
The foreign key, belongToOrder
, is mapped to the database column, Order_ID
, which is the same column as the placeholder CMP field, orderId
.
Both the foreign key, belongToOrder
, and the placeholder CMP field, orderId
, must point to the same database column.
<entity-deployment name="OrderItemBean" table="ORDER_ITEM"> <primkey-mapping> <cmp-field-mapping name="itemId" persistence-name="Item_ID" /> <cmp-field-mapping name="orderId" persistence-name="Order_ID" /> </primkey-mapping> <cmp-field-mapping name="price" persistence-name="Price" /> <cmp-field-mapping name="belongToOrder"> <entity-ref home="OrderBean"> <cmp-field-mapping name="belongToOrder" persistence-name="Order_ID" /> </entity-ref> </cmp-field-mapping> </entity-deployment> <entity-deployment name="OrderBean" table="ORDER"> <primkey-mapping> <cmp-field-mapping name="orderId" persistence-name="Order_ID" /> </primkey-mapping> <cmp-field-mapping name="orderDesc" persistence-name="Order_Description" /> <cmp-field-mapping name="items"> <collection-mapping table="ORDER_ITEM"> <primkey-mapping> <cmp-field-mapping name="OrderBean_orderId"> <entity-ref home="OrderBean"> <cmp-field-mapping name="OrderBean_orderId" persistence-name="Order_ID"/> </entity-ref> </cmp-field-mapping> </primkey-mapping> <value-mapping type="OrderItemLocal"> <cmp-field-mapping name="OrderItemBean_itemId"> <entity-ref home="OrderItemBean"> <cmp-field-mapping name="OrderItemBean_itemId"> <fields> <cmp-field-mapping name="OrderItemBean_itemId" persistence-name="Item_ID"/> <cmp-field-mapping name="OrderItemBean_orderId" persistence-name="Order_ID"/> </fields> </cmp-field-mapping> </entity-ref> </cmp-field-mapping> </value-mapping> </collection-mapping> </cmp-field-mapping> </entity-deployment>
Finally, you must update the bean implementation to work with both the placeholder CMP field and the foreign key.
In the ejbCreate
method, do the following:
Create the placeholder CMP field that takes the place of the foreign key field.
Set a value in the placeholder CMP field in the ejbCreate
method. This value is written out to the foreign key field in the database table.
In the ejbPostCreate
method, set the foreign key to the value in the duplicate CMP field.
Note: Since the foreign key is part of a primary key, it can only be set once. |
In our example, the CMP field, orderId
, is set in the ejbCreate
method and the relationship field, belongToOrder
, is set in the ejbPostCreate
method.
public OrderItemPK ejbCreate(OrderItem orderItem) throws CreateException { setItemId(orderItem.getItemId()); setOrderId(orderItem.getOrderId()); setPrice(orderItem.getPrice()); return new OrderItemPK(orderItem.getItemId(),orderItem.getOrderId()) ; } public void ejbPostCreate(OrderItem orderItem) throws CreateException { // when just after bean created try { Context ctx = new InitialContext(); OrderLocalHome orderHome = (OrderLocalHome)ctx.lookup("java:comp/env/OrderBean"); OrderLocal order = orderHome.findByPrimaryKey(orderItem.getOrderId()); setBelongToOrder(order); } catch(Exception e) { e.printStackTrace(); throw new EJBException(e); } }
The OrderItem
object that is passed into the ejbCreate
and ejbPostCreate
methods is as follows:
public class OrderItem implements java.io.Serializable { private Integer itemId; private Integer orderId; private Double price; public OrderItem(Integer itemId, Integer orderId, Double price) { this.itemId = itemId; this.orderId = orderId; this.price = price; } public Integer getItemId() { return itemId; } public void setItemId(Integer itemId) { this.itemId = itemId; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public boolean equals(Object other) { if(other instanceof OrderItem) { OrderItem orderItem = (OrderItem)other; if (itemId.equals(orderItem.getItemId()) && orderId.equals(orderItem.getOrderId()) && price.equals(orderItem.getPrice()) ) { return true; } } return false; } }