Finder Methods

Finder methods provide the programmer with a means to retrieve multiple entity beans from the persistent storage system and to write custom WHERE clauses to be used in such queries.

Entity beans generated by VAJ include a findByPrimaryKey() method.  Consequently, this method returns a single entity bean.  Thus, there is no convenient way to retrieve multiple beans in a single dbms query or to select beans on criteria other than the primary key.

VAJ supports customized finder methods that address these limitations.  Since they may be defined to return an enumeration of beans, multiple beans can be retrieved through a single dbms query.  Second, the programmer can also provide a WHERE clause to be used in a SELECT statement so that beans may be retrieved based on values from any filed or combination of fields.

An earlier, alternative to the current finder method provisions allowed full SQL statements to be used.  However, that approach has been deprecated for, apparently, two reasons.  First, if one needs to use the full power of SQL, one has the more appropriate alternative of using bean managed persistence.  Second, a SELECT that returned only a subset of the fields for the entity bean would violate the basic type constraints for that class. Thus, the currently favored finder helper methods support definition of a WHERE clause with the implication that all of the beans returned will have all of their fields defined and be set to their appropriate values.  If not all fields are needed by the application, the mapper or session bean class calling the finder method can construct whatever return data object is required.

Useful references can be found in the IBM Redbooks; see, in particular, those pertaining to EJBs and VAJ.

The discussion below includes a checklist of steps to construct a finder helper method illustrated by example code.  The entity bean is called Address, and the method to be developed is called: findByLastname().


Define Finder Method in the Home Interface

  1. Select the Home interface: e.g., AddressHome
  2. Add > Method.
  3. Name the method: public java.util.Enumeration findByLastName
  4. Add the appropriate parameter: e.g., String param
  5. In this same wizard, add two exceptions:  RemoteException and FinderException
  6. Finish and Save.
  7. The resulting code looks like this:  java.util.Enumeration findByLastName(String param) throws java.rmi.RemoteException, javax.ejb.FinderException;

 Define a Where Clause

  1. In the Types panel of the EJB tab, at the top left, select the Show Generated Types icon.
  2. Select the EJSJDBCPersisterAddressBean where Address will correspond to the name of your bean.
  3. Find the findByPrimaryKeySqlString field and copy the WHERE clause to use as a model
  4. Find the AddressBeanFinderHelper interface 
  5. Add the following line to the body of that interface:  public final static String findByLastNameWhereClause = "T1.name_last = ?";
  6. Replace name_last in the above example with whatever file names are appropriate for your bean and whatever other expressions are needed for your SELECT statement.
  7. Save everything.

Generate Deployed Code

Results

The following method will be added to your EJSJDBCPersisterAddressBean  class:

/**
 * Finder implementation for findByLastName.
 * @return EJSFinder
 * @param arg1 java.lang.String
 * @exception java.rmi.RemoteException The exception description.
 * @exception javax.ejb.FinderException The exception description.
 */
/* WARNING: THIS METHOD WILL BE REGENERATED. */

public EJSFinder findByLastName(java.lang.String arg1) throws java.rmi.RemoteException, javax.ejb.FinderException {
	
	ResultSet rs = null;
	PreparedStatement ps = null;
	EJSJDBCFinder result = null;

	try {
		preFind();
		ps = getMergedPreparedStatement(edu.jbs.address.beans.AddressBeanFinderHelper.findByLastNameWhereClause);
		for (int i=0; i<getMergedWhereCount(); i++) {
			// Injecting "java.lang.String arg1"
			if (arg1 == null) ps.setNull(1, 12); else ps.setString(i+1, arg1);
		}
		rs = ps.executeQuery();
		result = new EJSJDBCFinder(rs, this, ps);
	} catch (Exception exc) {
		try {
			if (rs != null) rs.close();
		} catch (SQLException sqlExc) {}
		if (ps != null) super.returnPreparedStatement(ps);
		throw new EJSPersistenceException("findByLastName failed:", exc);
	}
	
	return result;
	
}

Build the Client 

  1. Note that most searches other than byPrimaryKey can return multiple entries.  
  2. Build the code to accept Enumeration of ejbs as a result of the search.
  3. Be aware that unlike findByPrimaryKey, with returns an actual ejb, the Enumeration of objects returned by helper search is a set of stubs.  These stubs cannot be cast but, rather, must be narrowed.  
  4. See the code example that follows.
       public ObjectBean search(ObjectBean objBean) {

	  try  
		{

		String id = ((String)objBean.getValue("personID")).trim();	
		if ( id != null && !(id.equals("")) ) {
		aDBPerson = aDBPersonHome.findByPrimaryKey( new DBPersonKey(id) );
		}
		else {
			String nameLast = (String)objBean.getValue( "nameLast" );
			if ( nameLast != null && !(nameLast.equals("")) )  {
				java.util.Enumeration someDBPersons = aDBPersonHome.findByLastName( nameLast );
				if ( someDBPersons == null ) System.out.println( "someDBPersons is null" );
				else aDBPerson = (DBPerson)javax.rmi.PortableRemoteObject.narrow
                                  ( someDBPersons.nextElement(), DBPerson.class );
				if ( aDBPerson == null ) System.out.println("aDBPerson is null");
			}  // end if
			else  {
				System.out.println("Error: find by neither");// errior here
				return null;
			}
		}  // end else
		
		ResponseBean rb = getResponseBean( aDBPerson );
		rb.setResponseMessage( "Person search ok." );

		return rb;
		
	  }  catch ( FinderException e )  {
		System.out.println( "FinderException " + e + " caught in DBPersonMapper.search" );
		return null;
	  }  catch ( RemoteException e )  {
		System.out.println( "RemoteException " + e + " caught in DBPersonMapper.search" );
		return null;
	  }
	
      }

 

Test Using the Test Client