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