I continue to see this pattern again and again and it bothers me that I find
no "best practice" articles about it.

Consider a simple example: two CMP EJBs, Employer and Employee.
Employer has a couple of (read-only) summary attributes:
        int getNumEmployees(): defined as the number of all connected
Employees
        BigDecimal payroll(): defined as the sum of all connected Employee's
salary attributes
The attributes numEmployees and payroll need NOT be CMP fields on the
Employer and do NOT need to be in the database table, since they can be
calculated and I would like refreshed copies of these attributes each time
their getters are called.

Now here are a couple of alternative solutions I can conceive:
1. Write java methods which explicitly perform the calculations necessary,
with something like the following:
        public int getNumEmployees() <throws various exceptions> {
                int result = 0;
                Enumeration en = getEmployees();
                while (en.hasMoreElements()) {
                        en.nextElement();
                        result++;
                }
                return result;
        }
        public BigDecimal getPayroll() <throws various exceptions> {
                BigDecimal result = new BigDecimal("0");
                Enumeration en = getEmployees();
                Employee emp = null;
                while (en.hasMoreElements()) {
                        emp = ...  //narrow en.nextElement() to
Employee.class;
                        result = result.add(emp.getSalary());
                }
                return result;
        }
The problem with this is that getPayroll() requires that ALL the CMP fields
in ALL the owned Employee entities must be loaded in order to retrieve the
single attribute, salary, from each Employee. I believe that
getNumEmployees() would be a little more efficient IF getPayroll were not
called since getEmployees() can work without loading the entire state of
every Employee -- it should only load the primary keys the first time.

2. Write SQL select statements to perform the calculations and use pooled
Database connections to retrieve the values:
        public int getNumEmployees() <throws various exceptions> {
                int result;
                String sql = "select count(*) from employee EM where
EM.employer_id = " + id;
                Connection conn = MyConnectionPool.getConnection();
                ResultSet rs = conn.createStatement().executeQuery(sql);
                if (rs.next()) {
                        result = rs.getInt(1);
                }
                MyConnectionPool.returnConnection(conn); //return to
connection pool
                return result;
        }
        public BigDecimal getPayroll() <throws various exceptions> {
                BigDecimal result;
                String sql = "select sum(EM.salary) from employee EM where
EM.employer_id = " + id;
                Connection conn = MyConnectionPool.getConnection(); //from
connection pool
                ResultSet rs = conn.createStatement().executeQuery(sql);
                if (rs.next()) {
                        result = rs.getBigDecimal(1);
                }
                MyConnectionPool.returnConnection(conn); //return to
connection pool
                return result;
        }
The problem with this is that explicit SQL is being mixed in with the CMP
model, and a separate connection is used for these calculated attributes.
Whether the results of these getter methods should be cached for later gets
is also a question since in my EJB 1.1 non-compliant (VisualAge for Java
3.5.3) EJBs, the CMP fields in the Bean instance are NOT reinitialized each
time a new EJB instance is created (the previous corresponding field value
of the last Bean instance is used unless it is explicitly set in
ejbCreate()).

3. Store the "calculated" attributes as CMP fields, and perform no
calculation to obtain the values. This runs the risk of out-of-date data if
the Employee EJB is not written carefully to write back to the Employer EJB
every time a relevant change occurs (i.e. during ejbPostCreate(),
ejbRemove(), and during setPayroll(x)). It also runs a risk if an EJB
developer explicitly sets the payroll field without a call to setPayroll(x).
On the other hand, there is no calculation on-the-fly, so for large numbers
of records the retrieval is potentially faster. We also could run into a
data integrity on the database if someone uses SQL explicitly to change the
data to a row in the Employee table.

What are your thoughts as to the best way to accomplish this?

Charles May, Software Engineer
AFCO Credit/Mellon Financial Corp
email: mailto:[EMAIL PROTECTED]

The views expressed in this message are my own, and do not necessarily
represent the views of my employer.

*****************************************************************
DISCLAIMER:   The information contained in this e-mail may be confidential
and is intended solely for the use of the named addressee.  Access, copying
or re-use of the e-mail or any information contained therein by any other
person is not authorized.  If you are not the intended recipient please
notify us immediately by returning the e-mail to the originator.

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to