User: dsundstrom Date: 02/01/15 14:34:18 Modified: src/main/org/jboss/ejb/plugins/cmp/jdbc JDBCLoadRelationCommand.java Log: Added support for readahead and preload. Merged functions from JDBCFindByForeignKey. Converted field arrays to lists. Revision Changes Path 1.11 +304 -49 jboss/src/main/org/jboss/ejb/plugins/cmp/jdbc/JDBCLoadRelationCommand.java Index: JDBCLoadRelationCommand.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/cmp/jdbc/JDBCLoadRelationCommand.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- JDBCLoadRelationCommand.java 2002/01/05 12:08:51 1.10 +++ JDBCLoadRelationCommand.java 2002/01/15 22:34:17 1.11 @@ -10,28 +10,39 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.ejb.EJBException; +import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge; +import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData; +import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationMetaData; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData; import org.jboss.logging.Logger; +import org.jboss.util.FinderResults; /** * Loads relations for a particular entity from a relation table. * * @author <a href="mailto:[EMAIL PROTECTED]">Dain Sundstrom</a> - * @version $Revision: 1.10 $ + * @version $Revision: 1.11 $ */ public class JDBCLoadRelationCommand { - private JDBCStoreManager manager; - private Logger log; + private final JDBCStoreManager manager; + private final JDBCEntityBridge entity; + private final Logger log; public JDBCLoadRelationCommand(JDBCStoreManager manager) { this.manager = manager; + this.entity = manager.getEntityBridge(); // Create the Log log = Logger.getLogger( @@ -40,38 +51,22 @@ manager.getMetaData().getName()); } - public Set execute(JDBCCMRFieldBridge cmrField, Object pk) { - // get the key fields - JDBCCMPFieldBridge[] myKeyFields = cmrField.getTableKeyFields(); - JDBCCMPFieldBridge[] relatedKeyFields = - cmrField.getRelatedCMRField().getTableKeyFields(); - - // generate SQL - StringBuffer sql = new StringBuffer(); - String columnNamesClause = SQLUtil.getColumnNamesClause(cmrField.getRelatedCMRField().getTableKeyFields()); - String tableName = cmrField.getRelationMetaData().getTableName(); - String whereClause = SQLUtil.getWhereClause(cmrField.getTableKeyFields()); - - if (cmrField.getRelationMetaData().hasRowLocking()) - { - JDBCFunctionMappingMetaData rowLocking = manager.getMetaData().getTypeMapping().getRowLockingTemplate(); - if (rowLocking == null) - { - throw new IllegalStateException("row-locking is not allowed for this type of datastore"); - } - else - { - String[] args = new String[] {columnNamesClause, tableName, whereClause}; - sql.append(rowLocking.getFunctionSql(args)); - } - } - else - { - sql.append("SELECT ").append(columnNamesClause); - sql.append(" FROM ").append(tableName); - sql.append(" WHERE ").append(whereClause); - } + public Collection execute(JDBCCMRFieldBridge cmrField, Object pk) { + JDBCCMRFieldBridge relatedCMRField = cmrField.getRelatedCMRField(); + // get the read ahead cahces + ReadAheadCache readAheadCache = manager.getReadAheadCache(); + ReadAheadCache relatedReadAheadCache = + cmrField.getRelatedManager().getReadAheadCache(); + + // get the finder results associated with this context, if it exists + ReadAheadCache.EntityReadAheadInfo info = + readAheadCache.getEntityReadAheadInfo(pk); + List loadKeys = info.getLoadKeys(); + + // generate the sql + String sql = getSQL(cmrField, loadKeys.size()); + Connection con = null; PreparedStatement ps = null; try { @@ -79,39 +74,299 @@ con = cmrField.getRelationMetaData().getDataSource().getConnection(); // create the statement - if (log.isDebugEnabled()) - log.debug("Executing SQL: " + sql); + log.debug("Executing SQL: " + sql); ps = con.prepareStatement(sql.toString()); + // get the load fields + List myKeyFields = getMyKeyFields(cmrField); + List relatedKeyFields = getRelatedKeyFields(cmrField); + List preloadFields = getPreloadFields(cmrField); + // set the parameters - int index = 1; - for(int i=0; i<myKeyFields.length; i++) { - index = myKeyFields[i].setPrimaryKeyParameters(ps, index, pk); + int paramIndex = 1; + for(Iterator iter = loadKeys.iterator(); iter.hasNext();) { + Object key = iter.next(); + for(Iterator fields = myKeyFields.iterator(); fields.hasNext(); ) { + JDBCCMPFieldBridge field = (JDBCCMPFieldBridge)fields.next(); + paramIndex = field.setPrimaryKeyParameters(ps, paramIndex, key); + } } // execute statement ResultSet rs = ps.executeQuery(); + // initialize the results map + Map resultsMap = new HashMap(loadKeys.size()); + for(Iterator iter = loadKeys.iterator(); iter.hasNext();) { + resultsMap.put(iter.next(), new ArrayList()); + } + // load the results - Set result = new HashSet(); - Object[] pkRef = new Object[1]; + Object[] ref = new Object[1]; while(rs.next()) { - pkRef[0] = null; - index = 1; - for(int i=0; i<relatedKeyFields.length; i++) { - index = relatedKeyFields[i].loadPrimaryKeyResults( - rs, index, pkRef); + // reset the column index for this row + int index = 1; + + // ref must be reset to null before each load + ref[0] = null; + + // if we are loading more then one entity, load the pk from the row + Object loadedPk = pk; + if(loadKeys.size() > 1) { + // load the pk + for(Iterator fields=myKeyFields.iterator(); fields.hasNext();) { + JDBCCMPFieldBridge field = (JDBCCMPFieldBridge)fields.next(); + index = field.loadPrimaryKeyResults(rs, index, ref); + } + loadedPk = ref[0]; + } + + // load the fk + ref[0] = null; + for(Iterator fields = relatedKeyFields.iterator(); + fields.hasNext();) { + JDBCCMPFieldBridge field = (JDBCCMPFieldBridge)fields.next(); + index = field.loadPrimaryKeyResults(rs, index, ref); } - result.add(pkRef[0]); + Object loadedFk = ref[0]; + + if(loadedFk != null) { + // add this value to the list for loadedPk + List results = (List)resultsMap.get(loadedPk); + results.add(loadedFk); + + // if the related cmr field is single valued we can pre-load + // the reverse relationship + if(relatedCMRField.isSingleValued()) { + relatedReadAheadCache.addPreloadData( + loadedFk, + relatedCMRField, + Collections.singletonList(loadedPk)); + } + + // read the preload fields + for(Iterator iter=preloadFields.iterator(); iter.hasNext();) { + JDBCFieldBridge field = (JDBCFieldBridge)iter.next(); + ref[0] = null; + + // read the value and store it in the readahead cache + index = field.loadArgumentResults(rs, index, ref); + relatedReadAheadCache.addPreloadData(loadedFk, field, ref[0]); + } + } } + // set all of the preloaded values + for(Iterator iter=resultsMap.keySet().iterator(); iter.hasNext();) { + Object key = iter.next(); + if(!key.equals(pk)) { + readAheadCache.addPreloadData( + key, cmrField, (List)resultsMap.get(key)); + } + } + + // get the real result list + List result = (List)resultsMap.get(pk); + + // Convert the pk collection into finder results + FinderResults finderResults = new FinderResults( + result, null, null, null); + + // add results to the cache + if(!cmrField.getReadAhead().isNone()) { + relatedReadAheadCache.addFinderResult(finderResults); + } + // success return result; + } catch(EJBException e) { + throw e; } catch(Exception e) { - throw new EJBException("Load relation by foreign-key failed", e); + throw new EJBException("Load relation failed", e); } finally { JDBCUtil.safeClose(ps); JDBCUtil.safeClose(con); } + } + + private String getSQL(JDBCCMRFieldBridge cmrField, int keyCount) { + + List myKeyFields = getMyKeyFields(cmrField); + List relatedKeyFields = getRelatedKeyFields(cmrField); + List preloadFields = getPreloadFields(cmrField); + String relationTable = getRelationTable(cmrField); + String relatedTable = cmrField.getRelatedEntity().getTableName(); + + // do we need to join the relation table and the related table + boolean join = (preloadFields.size() > 0 && + !relationTable.equals(relatedTable)); + + // aliases for the tables, only required if we are joining the tables + String relationTableAlias = ""; + String relatedTableAlias = ""; + if(join) { + relationTableAlias = relationTable; + relatedTableAlias = relatedTable; + } + + // + // column names clause + // + StringBuffer columnNamesClause = new StringBuffer(); + if(keyCount > 1) { + columnNamesClause.append( + SQLUtil.getColumnNamesClause(myKeyFields, relationTableAlias)); + columnNamesClause.append(", "); + } + columnNamesClause.append( + SQLUtil.getColumnNamesClause(relatedKeyFields, relationTableAlias)); + if(preloadFields.size() > 0) { + columnNamesClause.append(", "); + columnNamesClause.append( + SQLUtil.getColumnNamesClause(preloadFields, relatedTableAlias)); + } + + // + // from clause + // + StringBuffer fromClause = new StringBuffer(); + fromClause.append(relationTable); + if(join) { + fromClause.append(", ").append(relatedTable); + } + + // + // where clause + // + StringBuffer whereClause = new StringBuffer(); + // add the join + if(join) { + // join the tables + whereClause.append("("); + whereClause.append(SQLUtil.getJoinClause( + relatedKeyFields, + relationTable, + cmrField.getRelatedEntity().getPrimaryKeyFields(), + relatedTable)); + whereClause.append(") AND ("); + } + // add the keys + String pkWhere = SQLUtil.getWhereClause(myKeyFields, relationTableAlias); + for(int i=0; i<keyCount; i++) { + if(i > 0) { + whereClause.append(" OR "); + } + whereClause.append("(").append(pkWhere).append(")"); + } + if(join) { + whereClause.append(")"); + } + + // + // assemble pieces into final statement + // + JDBCFunctionMappingMetaData selectTemplate = getSelectTemplate(cmrField); + if(selectTemplate != null) { + String[] args = new String[] { + columnNamesClause.toString(), + fromClause.toString(), + whereClause.toString()}; + return selectTemplate.getFunctionSql(args); + } else { + StringBuffer sql = new StringBuffer( + 7 + columnNamesClause.length() + + 6 + fromClause.length() + + 7 + whereClause.length()); + + sql.append("SELECT ").append(columnNamesClause); + sql.append(" FROM ").append(fromClause); + sql.append(" WHERE ").append(whereClause); + return sql.toString(); + } + } + + private List getMyKeyFields(JDBCCMRFieldBridge cmrField) { + if(cmrField.getRelationMetaData().isTableMappingStyle()) { + // relation table + return cmrField.getTableKeyFields(); + } else if(cmrField.getRelatedCMRField().hasForeignKey()) { + // related has foreign key + return cmrField.getRelatedCMRField().getForeignKeyFields(); + } else { + // i have foreign key + return entity.getPrimaryKeyFields(); + } + } + + private List getRelatedKeyFields(JDBCCMRFieldBridge cmrField) { + if(cmrField.getRelationMetaData().isTableMappingStyle()) { + // relation table + return cmrField.getRelatedCMRField().getTableKeyFields(); + } else if(cmrField.getRelatedCMRField().hasForeignKey()) { + // related has foreign key + return cmrField.getRelatedEntity().getPrimaryKeyFields(); + } else { + // i have foreign key + return cmrField.getForeignKeyFields(); + } + } + + private List getPreloadFields(JDBCCMRFieldBridge cmrField) { + if(!cmrField.getReadAhead().isOnFind()) { + return Collections.EMPTY_LIST; + } + String eagerLoadGroup = cmrField.getReadAhead().getEagerLoadGroup(); + return cmrField.getRelatedEntity().getLoadGroup(eagerLoadGroup); + } + + private String getRelationTable(JDBCCMRFieldBridge cmrField) { + if(cmrField.getRelationMetaData().isTableMappingStyle()) { + // relation table + return cmrField.getRelationMetaData().getTableName(); + } else if(cmrField.getRelatedCMRField().hasForeignKey()) { + // related has foreign key + return cmrField.getRelatedEntity().getTableName(); + } else { + // i have foreign key + return entity.getTableName(); + } + } + + private JDBCFunctionMappingMetaData getSelectTemplate( + JDBCCMRFieldBridge cmrField) { + + JDBCFunctionMappingMetaData selectTemplate = null; + if(cmrField.getRelationMetaData().isTableMappingStyle()) { + // relation table + if(cmrField.getRelationMetaData().hasRowLocking()) { + selectTemplate = + cmrField.getRelationMetaData().getTypeMapping().getRowLockingTemplate(); + if(selectTemplate == null) { + throw new IllegalStateException("row-locking is not allowed " + + "for this type of datastore"); + } + } + } else if(cmrField.getRelatedCMRField().hasForeignKey()) { + // related has foreign key + if(cmrField.getRelatedEntity().getMetaData().hasRowLocking()) { + selectTemplate = + cmrField.getRelatedEntity().getMetaData().getTypeMapping().getRowLockingTemplate(); + if(selectTemplate == null) { + throw new IllegalStateException("row-locking is not allowed " + + "for this type of datastore"); + } + } + } else { + // i have foreign key + if(entity.getMetaData().hasRowLocking()) { + selectTemplate = + entity.getMetaData().getTypeMapping().getRowLockingTemplate(); + if(selectTemplate == null) { + throw new IllegalStateException("row-locking is not allowed " + + "for this type of datastore"); + } + } + } + return selectTemplate; } }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development