Loading and Storing an Entity

   

Other than executing business methods , most of the work done by your entity bean involves keeping its state in synch with its corresponding data in the database. This work is done by your ejbLoad and ejbStore methods.

Implementing ejbLoad

The container calls ejbLoad when an entity is activated and needs to guarantee that its state in memory matches what's in the database. Listing 6.7 shows the ejbLoad method for EnglishAuctionBean .

Listing 6.7 ejbLoad “A BMP ejbLoad Method Retrieves Data from the Database
 package com.que.ejb20.auction.model;  ...  public class EnglishAuctionBean extends AbstractEntity implements EntityBean {   ...    public void ejbLoad() {     Connection con = null;      PreparedStatement stmt = null;      ResultSet rs = null;      try {       con = BMPHelper.getConnection("auctionSource");        // build a select statement for the auction fields        stmt = con.prepareStatement("SELECT Name, Description, Status, " +          "StartingBid, MinBidIncrement, ReserveAmount, StartDate, " +          "ScheduledEndDate, ActualEndDate, LeadingBidId, WinningBidId, " +          "ItemId, Quantity FROM auction WHERE id = ?");        Integer primaryKey = (Integer)ctx.getPrimaryKey();        stmt.setInt(1, primaryKey.intValue());        // execute the select        rs = stmt.executeQuery();        boolean found = rs.next();        if (found) {         // transfer the result set values into the instance fields          id = primaryKey;          name = rs.getString("Name");          description = rs.getString("Description");          status = rs.getString("Status");          // the SQL numeric type is returned as a BigDecimal          BigDecimal bd = rs.getBigDecimal("StartingBid");          startingBid = bd != null ? new Double(bd.doubleValue()) : null;          bd = rs.getBigDecimal("MinBidIncrement");          minBidIncrement = bd != null ? new Double(bd.doubleValue()) : null;          bd = rs.getBigDecimal("ReserveAmount");          reserveAmount = bd != null ? new Double(bd.doubleValue()) : null;          startDateTime = rs.getTimestamp("StartDate");          scheduledEndDateTime = rs.getTimestamp("ScheduledEndDate");          actualEndDateTime = rs.getTimestamp("ActualEndDate");          leadingBidId = (Integer)rs.getObject("LeadingBidId");          winningBidId = (Integer)rs.getObject("WinningBidId");          itemId = (Integer)rs.getObject("ItemId");          quantity = (Integer)rs.getObject("Quantity");          // will load the item when requested          item = null;          // will load the bids when requested          setBids(null);          leadingBid = null;          winningBid = null;        }        else {         throw new EJBException("Error loading data for auction id " +            primaryKey);        }      }      catch (SQLException e) {       // throw a system exception if a database access error occurs        throw new EJBException;      }      finally {       // close the connection        BMPHelper.cleanup(stmt, con);      }    }    ...  } 

Within ejbLoad , you can use an instance's EntityContext to get the primary key assigned to it. You can then build a select statement that retrieves the entity's attribute values from the database. An entity also needs to retrieve its associated objects or at least load the key values it can use to access them when they're needed. Chapter 17, "Addressing Performance," covers some options you can employ with BMP but for now, the ejbLoad method for the auction defers any reading of its list of bids until they're needed. The leading and winning bids and the auction's item assignment are simply held as primary key values at this point as well. This is the nice thing about BMP: You can decide what you want to load at this point quite easily.

Implementing ejbStore

The counterpart to ejbLoad is the ejbStore method. The container calls ejbStore when a transaction that includes an entity object commits or when the entity is about to be passivated. You have to provide an implementation of ejbStore that writes an entity's persistent state to the database. Listing 6.8 shows this method for EnglishAuctionBean .

Listing 6.8 ejbStore “A BMP ejbStore Method Writes an Entity's State to the Database
 package com.que.ejb20.auction.model;  ...  public class EnglishAuctionBean extends AbstractEntity implements EntityBean {   ...    private Collection bidsToStore = new ArrayList();    ...    public void ejbStore() {     Connection con = null;      PreparedStatement stmt = null;      try {       con = BMPHelper.getConnection("auctionSource");        if (!bidsToStore.isEmpty()) {         // store bids added during this transaction          stmt = con.prepareStatement(           "INSERT INTO bid (id, AuctionId, BidderId, BidDateTime, Amount, " +            "TransactionId) VALUES (?,?,?,?,?,?)");          Iterator iter = bidsToStore.iterator();          while (iter.hasNext()) {           Bid newBid = (Bid)iter.next();            stmt.setInt(1, newBid.getId().intValue());            stmt.setInt(2, newBid.getAuctionId().intValue());            stmt.setInt(3, newBid.getBidderId().intValue());            stmt.setTimestamp(4, newBid.getDateTimeSubmitted());            stmt.setDouble(5, newBid.getAmount().doubleValue());            stmt.setString(6, newBid.getTransactionId());            int rowsInserted = stmt.executeUpdate();            if (rowsInserted != 1) {             throw new EJBException(               "Could not insert bid into the database");            }          }          bidsToStore.clear();          stmt.close();        }        // build an update statement to write the auction state to the database        stmt = con.prepareStatement("UPDATE auction SET Name = ?, " +          "Description = ?, Status = ?, StartingBid = ?, MinBidIncrement = ?, " +          "ReserveAmount = ?, StartDate = ?, ScheduledEndDate = ?, " +          "ActualEndDate = ?, LeadingBidId = ?, WinningBidId = ?, ItemId = ?, " +          "Quantity = ? FROM auction WHERE id = ?");        stmt.setString(1, getName());        stmt.setString(2, getDescription());        stmt.setString(3, getStatus());        if (getStartingBid() != null) {         stmt.setDouble(4, getStartingBid().doubleValue());        }        else {         stmt.setNull(4, java.sql.Types.DOUBLE);        }        if (getMinBidIncrement() != null) {         stmt.setDouble(5, getMinBidIncrement().doubleValue());        }        else {         stmt.setNull(5, java.sql.Types.DOUBLE);        }        if (getReserveAmount() != null) {         stmt.setDouble(6, getReserveAmount().doubleValue());        }        else {         stmt.setNull(6, java.sql.Types.DOUBLE);        }        stmt.setTimestamp(7, getStartDateTime());        stmt.setTimestamp(8, getScheduledEndDateTime());        stmt.setTimestamp(9, getActualEndDateTime());        if (getLeadingBid() != null) {         stmt.setInt(10, getLeadingBid().getId().intValue());        }        else {         stmt.setNull(10, java.sql.Types.INTEGER);        }        if (getWinningBid() != null) {         stmt.setInt(11, getWinningBid().getId().intValue());        }        else {         stmt.setNull(11, java.sql.Types.INTEGER);        }        if (getItemId() != null) {         stmt.setInt(12, getItemId().intValue());        }        else {         stmt.setNull(12, java.sql.Types.INTEGER);        }        if (getQuantity() != null) {         stmt.setInt(13, getQuantity().intValue());        }        else {         stmt.setNull(13, java.sql.Types.INTEGER);        }        // set the primary key for the WHERE clause        stmt.setInt(14, getId().intValue());        // execute the update and throw an exception if it fails        int rowsUpdated = stmt.executeUpdate();        if (rowsUpdated != 1) {         throw new EJBException("Error storing data for auction id " + id);        }      }      catch (SQLException e) {       // throw a system exception if a database access error occurs        throw new EJBException;      }      finally {       // close the connection        BMPHelper.cleanup(stmt, con);      }    }    ...  } 

Besides updating the state of the auction, ejbStore also inserts any new Bid objects created for the auction into the database. The complete listing for EnglishAuctionBean included on the CD shows how bidsToStore is used by the submitBid method. Listing 6.9 shows the implementation of Bid .

Listing 6.9 Bid.java “Dependent Object Implementation
 package com.que.ejb20.auction.model;  /**   * Title:        Bid<p>   * Description:  An auction bid<p>   */  import java.sql.Timestamp;  import com.que.ejb20.auction.view.BidView;  public class Bid {   private Integer id;    private Integer auctionId;    private Integer bidderId;    private Timestamp dateTimeSubmitted;    private Double amount;    private String transactionId;    public Bid() {   }    public Bid(Integer newId, Integer newAuctionId, Integer newBidderId,      Timestamp newDateTimeSubmitted, Double newAmount, String newTransactionId) {       setId(newId);        setAuctionId(newAuctionId);        setBidderId(newBidderId);        setDateTimeSubmitted(newDateTimeSubmitted);        setAmount(newAmount);        setTransactionId(newTransactionId);      }    public Integer getId() {     return id;    }    protected void setId(Integer newId) {     if (newId != null) {       id = newId;      }      else {       throw new IllegalArgumentException("Bid id must be non-null");      }    }    public Integer getAuctionId() {     return auctionId;    }    public void setAuctionId(Integer newAuctionId) {     if (newAuctionId != null) {       auctionId = newAuctionId;      }      else {       throw new IllegalArgumentException("Bid auction id must be non-null");      }    }    public Integer getBidderId() {     return bidderId;    }    public void setBidderId(Integer newBidderId) {     if (newBidderId != null) {       bidderId = newBidderId;      }      else {       throw new IllegalArgumentException("Bid bidder id must be non-null");      }    }    public Timestamp getDateTimeSubmitted() {     return dateTimeSubmitted;    }    public void setDateTimeSubmitted(Timestamp newDateTimeSubmitted) {     if (newDateTimeSubmitted != null) {       dateTimeSubmitted = newDateTimeSubmitted;      }      else {       throw new IllegalArgumentException("Bid time must be non-null");      }    }    public Double getAmount() {     return amount;    }    public void setAmount(Double newAmount) {     if ((newAmount != null) && (newAmount.doubleValue() >= 0.0)) {       amount = newAmount;      }      else {       throw new IllegalArgumentException(         "Bid amount cannot be null or negative");      }    }    public String getTransactionId() {     return transactionId;    }    public void setTransactionId(String newTransactionId) {     if (newTransactionId != null) {       transactionId = newTransactionId;      }      else {      throw new IllegalArgumentException("Bid transaction id must be non-null");      }    }    public BidView getView() {     BidView view = new BidView(getAuctionId(), getBidderId(),        getDateTimeSubmitted(), getAmount(), getTransactionId());      return view;    }  } 

As you can see, the most complicated part of ejbStore for the auction entity is checking for potential null values for its attributes and then calling the appropriate methods of PreparedStatement . Besides inserting new bids, an auction's associations are taken care of as long as you write all the foreign key values out to the database.

The problem with this simple implementation of ejbStore is that it isn't very efficient. It always writes to the database when it's called, and it always writes every attribute even if all of them haven't changed. You'll see alternatives to this discussed in Chapter 17.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

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