Creating custom findersWhen you create an entity bean, you always get the findByPrimaryKey finder method on the home interface.. Open the EJB deployment descriptor, switch to the Beans p
Trang 1This time around, the association relationship is many-to-many Simply turn both role names to plural and set both Multiplicity fields to Many Click Finish to complete the wizard
Figure 12-27 shows the EJB deployment descriptor with the Account bean selected
Figure 12-27 EJB deployment descriptor editor after creating relationships Save the changes and close the editor
You may now inspect the changes the wizard made to your EJBs In the J2EE Hierarchy view, double-click the AccountLocal interface to open it with the Java editor The following methods should have been added:
public java.util.Collection getTransRecords();
public void setTransRecords(java.util.Collection aTransRecords);
public java.util.Collection getCustomers();
public void setCustomers(java.util.Collection aCustomers);
Close the editor
Updating the TransRecord create method
You might recall that we have updated the TransRecordcreate method before (Figure 12-20 on page 399 and Figure 12-21 on page 400) In that opportunity,
we added parameters to the create method to make sure no transaction record was created unless the transaction type and amount were specified Now we
Trang 2Update the TransRecordLocalHome interface so that the create method has this signature:
public itso.ejb.model.entity.TransRecordLocal create(String transType,
int transAmt, AccountLocal account) throws javax.ejb.CreateException;
Note that the only change was the additional AccountLocal parameter Save your changes and close the editor
Because we changed the create method on the home interface, we also have to change the ejbCreate and ejbPostCreate methods in the TransRecordBean class Open the class and perform the changes described in Figure 12-28
Figure 12-28 TransRecord bean’s updated ejbCreate and ejbPostCreate methods
Save your changes and close the editor
public java.util.Date ejbCreate(String transType,
java.math.BigDecimal transAmt, AccountLocal account)
throws javax.ejb.CreateException {
setTimeStamp(new java.util.Date());
setTransType(transType);
setTransAmt(transAmt);
return null;
}
public void ejbPostCreate(String transType,
java.math.BigDecimal transAmt, AccountLocal account)
throws javax.ejb.CreateException {
setAccount(account);
}
Note: The setAccount method was added when we created the association relationship between the Account and the TransRecord beans This method cannot be called from the ejbCreate method According to the specification, during ejbCreate the instance cannot acquire a reference to the associated entity object, and that reference is required by the setAccount method
In the ejbPostCreate method, on the other hand, the instance may reference the associated entity object Thus, a call to setAccount can be made
Trang 3Creating custom finders
When you create an entity bean, you always get the findByPrimaryKey finder method on the home interface Sometimes, though, you need to find an entity based on criteria other than just the primary key For these occasions, the EJB 2.0 specification provides a query language called EJB QL Custom finder methods are declared in the home interface and defined in the EJB deployment descriptor using the EJB QL
We do not require any custom finders for our RedBank example But we will add one nonetheless so that you know how you would do it on your own projects Our finder will look for all accounts that have a balance greater than a given value Open the EJB deployment descriptor, switch to the Beans page, and select the Account bean from the list Scroll down to the Queries section (Figure 12-29)
Figure 12-29 Defining queries with the EJB deployment descriptor editor Click Add to open the Add Finder Descriptor wizard (Figure 12-30):
Here you have the option to define the query descriptor to either a new finder method or to one previously declared in the bean’s home interface Select New, as the only finder we have in our AccountLocalHome interface is the default findByPrimaryKey Application Developer will take care of updating the home interface for you by adding the declaration of the new finder method
The Method Type field lets you select whether you want to create a descriptor
Trang 4Figure 12-30 Adding a new finder method (page 1)
The Type field would let you select to which home interface, either local or remote, you would like the finder method promoted You do not get an option
in this case because our Account bean only exposes a local view
In the Name field, type findGoldAccounts as the name of the finder method
Click Add to define a BigDecimal parameter
Select java.util.Collection in the Return type field Finder and ejbSelect methods may return either a collection of objects, or just one instance of the object’s component interface types
Click Next to proceed to the final page (Figure 12-31):
The last wizard page lets you type a description to the query and the query statement You may optionally select a sample query as a starting point, for example, FindByPrimaryKey
Complete the query:
select object(o) from Account o where o.balance > ?1
Click Finish to end the dialog
Trang 5Figure 12-31 Adding a new finder method (page 2) The EJB deployment descriptor with the query is shown in Figure 12-32
Figure 12-32 EJB deployment descriptor after adding query
Trang 6Object-relational mapping
CMP entity beans delegate its persistence to the container But what does this mean? Simply, as bean providers, we do not have to code any database access directly into our entity beans—we let the container do it for us The only thing we must provide are the abstract data-to-object mappings that map the fields in our bean to a database, and the abstract methods that correlate to those fields The container knows that data is to be persisted because the mappings are defined in the deployment descriptor, and during deployment, the JDBC code to perform the operations is generated by the container When the beans are actually deployed, associations to real data sources can be made to dynamically bind the bean to the data In this way, the CMPs are abstract classes that associate to data, but do not provide any implementation for accessing data themselves
Of course, this is an oversimplification: everything is not completely abstracted away and hidden from the developer because the developer has to have some knowledge of the underlying data sources at the time of development, to create and test the mappings in the first place It’s just that defining the deployment descriptor abstract mappings is a separate and distinct process from associating those mappings to a real data source at deployment time To facilitate
deployment and testing, Application Developer gives you the tools and means to both define the mappings and create deployment bindings at the same time Hiding the knowledge is not really the primary reason for having an abstraction such as this, where the definition and development of the bean and its mappings
is separate from the dynamic run-time bindings of the bean The goal, rather, is
to enable the developer to work with object views of the domain data instead of data views and writing SQL But another subtle benefit is also achieved By having a separation of these development and persistence concerns, one is free
to focus on the business logic The CMP can be developed largely independently
of the data source, and allows a clear separation of business and data access logic This is one of the fundamental axioms of aspect oriented programming, where the aspect of persistence can be removed from the development process, and applied later, in this case, at deployment time
Application Developer offers three different mapping strategies: top down, meet
in the middle, and bottom up:
Top down is when you start from an object oriented model and let the
environment generate the data model automatically for you, including the object-relational mapping and the DDL that you would use to create the tables
in the database
Note: This strategy is preferred when the data backend does not exist and
will be created from scratch
Trang 7 Bottom up is when you start from a data model and let Application Developer
generate the object model automatically for you, including the creation of the entity beans based on tables and columns that you select
Meet in the middle is the compromise strategy, in which you keep both your
existing object oriented and data models, creating a mapping between the two The mapping process is usually started by Application Developer, based
on cues like attribute names and types, and completed manually by you For now we will use the meet in the middle strategy because we do have an existing database for application data
Mapping the model to the EJBBANK database
In the J2EE Hierarchy view, select the EJB module (ItsoProGuideEJB) and select Generate -> EJB to RDB Mapping from its context menu
In the EJB to RDB Mapping panel, select Create a new backend folder and click Next Application Developer enables us to map an entity bean to multiple backend stores, for example, different relational database systems (Figure 12-33)
Note: This strategy is not recommended for object oriented applications,
because the data model is less expressive than the object model It should
be used only for prototyping purposes
Trang 8In the Create new EJB/RDB Mapping panel, select Meet In the Middle and click Next
The Database Connection pane opens, as shown in Figure 12-34
Figure 12-34 Database connection
Enter the connection name (EJBBankConnection) and the database name (EJBBank) The rest of the options should be left to their default values, that are:
The user ID and password fields can be left empty if your user ID is
authorized to the EJBBANK database and tables Otherwise use the user ID that was used to install DB2 and to define the EJBBANK database
For database vendor, make sure that DB2 UDB V7.2 is selected
IBM DB2 APP DRIVER
Trang 9 The class location is prefilled if DB2 is installed on your system Make sure that the location points to the db2java.zip file
You can use the Filters button to limit the number of table definitions that are imported Although we do not use all the tables for our model, we do not use a filter
Click Next to open the Selective Database Import panel Select the four tables that are required for our model (Figure 12-35)
Figure 12-35 Selecting the tables for import Click Next and select Match by Name (Figure 12-36) This option should match entities and attributes to tables and columns with the same name, thus
minimizing your manual work
Trang 10Figure 12-36 Matching options
Click Finish to complete the database schema import and to open the mapping editor (Figure 12-37):
As you can see, matching by name has already mapped the beans to the correct tables, and some fields to the correct columns The mapped items carry a little triangle as an indicator and they are listed in the bottom pane
Some fields have not been matched automatically We can perform the manual mapping by dragging and dropping attributes in the left pane to relational columns on the right, or vice-versa A bean must be mapped to a table before you can map the attributes of the bean to the columns
Relationships can be mapped as if they were regular fields
The arrows in Figure 12-37 indicate what manual mapping must be
performed, solid for attributes and dotted for relationships:
– Customer id < > CUSTOMER CUSTOMERID
– Account id < > ACCOUNT ACCID
– Account type < > ACCOUNT ACCTYPE
– TransRecord timeStamp < > TRANSRECORD TRANSID
– Account customers < > CUSTACCT CAtoCustomer
– Customer accounts < > CUSTACCT CAtoAccount
– TransRecord account < > TRANSRECORD AccountTransrecord
Note: The last mapping also maps AccounttransRecords (in a 1:m
relationship only one mapping is required)
Note: You can alternatively select an item in the left pane and one in the right
pane and select Create Mapping from the context menu This is the same as drag and drop