All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.queries.ReadAllQuery Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Oracle - initial API and implementation from Oracle TopLink
 *     04/01/2011-2.3 Guy Pelletier 
 *       - 337323: Multi-tenant with shared schema support (part 2)
 *     09/09/2011-2.3.1 Guy Pelletier 
 *       - 356197: Add new VPD type to MultitenantType
 ******************************************************************************/  
package org.eclipse.persistence.queries;

import java.util.*;
import java.sql.*;

import org.eclipse.persistence.internal.databaseaccess.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
import org.eclipse.persistence.internal.queries.*;
import org.eclipse.persistence.internal.sessions.remote.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.sessions.SessionProfiler;
import org.eclipse.persistence.sessions.remote.*;
import org.eclipse.persistence.tools.profiler.QueryMonitor;

/**
 * 

Purpose: * Concrete class for all read queries involving a collection of objects. *

*

Responsibilities: * Return a container of the objects generated by the query. * Implements the inheritance feature when dealing with abstract descriptors * * @author Yvon Lavoie * @since TOPLink/Java 1.0 */ public class ReadAllQuery extends ObjectLevelReadQuery { /** Used for collection and stream support. */ protected ContainerPolicy containerPolicy; /** Used for Oracle HierarchicalQuery support */ protected Expression startWithExpression; protected Expression connectByExpression; protected List orderSiblingsByExpressions; /** * PUBLIC: * Return a new read all query. * A reference class must be specified before execution. * It is better to provide the class and expression builder on construction to ensure a single expression builder is used. * If no selection criteria is specified this will read all objects of the class from the database. */ public ReadAllQuery() { super(); setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); } /** * PUBLIC: * Return a new read all query. * It is better to provide the class and expression builder on construction to ensure a single expression builder is used. * If no selection criteria is specified this will read all objects of the class from the database. */ public ReadAllQuery(Class classToRead) { this(); this.referenceClass = classToRead; } /** * PUBLIC: * Return a new read all query for the class and the selection criteria. */ public ReadAllQuery(Class classToRead, Expression selectionCriteria) { this(); this.referenceClass = classToRead; setSelectionCriteria(selectionCriteria); } /** * PUBLIC: * Return a new read all query for the class. * The expression builder must be used for all associated expressions used with the query. */ public ReadAllQuery(Class classToRead, ExpressionBuilder builder) { this(); this.defaultBuilder = builder; this.referenceClass = classToRead; } /** * PUBLIC: * Return a new read all query. * The call represents a database interaction such as SQL, Stored Procedure. */ public ReadAllQuery(Class classToRead, Call call) { this(); this.referenceClass = classToRead; setCall(call); } /** * PUBLIC: * Return a query by example query to find all objects matching the attributes of the example object. */ public ReadAllQuery(Object exampleObject, QueryByExamplePolicy policy) { this(); setExampleObject(exampleObject); setQueryByExamplePolicy(policy); } /** * PUBLIC: * The expression builder should be provide on creation to ensure only one is used. */ public ReadAllQuery(ExpressionBuilder builder) { this(); this.defaultBuilder = builder; } /** * PUBLIC: * Create a read all query with the database call. */ public ReadAllQuery(Call call) { this(); setCall(call); } /** * PUBLIC: * Order the query results by the object's attribute or query key name. */ public void addAscendingOrdering(String queryKeyName) { addOrdering(getExpressionBuilder().get(queryKeyName).ascending()); } /** * INTERNAL: *

This method is called by the object builder when building an original. * It will cause the original to be cached in the query results if the query * is set to do so. */ @Override public void cacheResult(Object unwrappedOriginal) { Collection container = (Collection)getTemporaryCachedQueryResults(); if (container == null) { container = (Collection)getContainerPolicy().containerInstance(); setTemporaryCachedQueryResults(container); } getContainerPolicy().addInto(unwrappedOriginal, container, getSession()); } /** * INTERNAL: * The cache check is done before the prepare as a hit will not require the work to be done. */ @Override protected Object checkEarlyReturnLocal(AbstractSession session, AbstractRecord translationRow) { // Check for in-memory only query. if (shouldCheckCacheOnly()) { // assert !isReportQuery(); if (shouldUseWrapperPolicy()) { getContainerPolicy().setElementDescriptor(this.descriptor); } // PERF: Fixed to not query each unit of work cache (is not conforming), // avoid hashtable and primary key indexing. // At some point we may need to support some kind of in-memory with conforming option, // but we do not currently allow this. AbstractSession rootSession = session; while (rootSession.isUnitOfWork()) { rootSession = ((UnitOfWorkImpl)rootSession).getParent(); } Vector allCachedVector = rootSession.getIdentityMapAccessor().getAllFromIdentityMap(getSelectionCriteria(), getReferenceClass(), translationRow, getInMemoryQueryIndirectionPolicyState(), false); // Must ensure that all of the objects returned are correctly registered in the unit of work. if (session.isUnitOfWork()) { allCachedVector = ((UnitOfWorkImpl)session).registerAllObjects(allCachedVector); } this.isCacheCheckComplete = true; return getContainerPolicy().buildContainerFromVector(allCachedVector, session); } else { return null; } } /** * INTERNAL: * Check to see if a custom query should be used for this query. * This is done before the query is copied and prepared/executed. * null means there is none. */ @Override protected DatabaseQuery checkForCustomQuery(AbstractSession session, AbstractRecord translationRow) { checkDescriptor(session); // Check if user defined a custom query. if (isCustomQueryUsed() == null) { setIsCustomQueryUsed((!isUserDefined()) && isExpressionQuery() && (getSelectionCriteria() == null) && isDefaultPropertiesQuery() && (!hasOrderByExpressions()) && (this.descriptor.getQueryManager().hasReadAllQuery())); } if (isCustomQueryUsed().booleanValue()) { return this.descriptor.getQueryManager().getReadAllQuery(); } else { return null; } } /** * INTERNAL: * Clone the query. */ @Override public Object clone() { ReadAllQuery cloneQuery = (ReadAllQuery)super.clone(); // Don't use setters as that will trigger unprepare cloneQuery.containerPolicy = this.containerPolicy.clone(cloneQuery); return cloneQuery; } /** * INTERNAL: * Conform the result if specified. */ protected Object conformResult(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) { if (getSelectionCriteria() != null) { ExpressionBuilder builder = getSelectionCriteria().getBuilder(); builder.setSession(unitOfWork.getRootSession(null)); builder.setQueryClass(getReferenceClass()); } // If the query is redirected then the collection returned might no longer // correspond to the original container policy. CR#2342-S.M. ContainerPolicy cp; if (getRedirector() != null) { cp = ContainerPolicy.buildPolicyFor(result.getClass()); } else { cp = getContainerPolicy(); } // This code is now a great deal different... For one, registration is done // as part of conforming. Also, this should only be called if one actually // is conforming. // First scan the UnitOfWork for conforming instances. // This will walk through the entire cache of registered objects. // Let p be objects from result not in the cache. // Let c be objects from cache. // Presently p intersect c = empty set, but later p subset c. // By checking cache now doesConform will be called p fewer times. Map indexedInterimResult = unitOfWork.scanForConformingInstances(getSelectionCriteria(), getReferenceClass(), arguments, this); Cursor cursor = null; // In the case of cursors just conform/register the initially read collection. if (cp.isCursorPolicy()) { cursor = (Cursor)result; cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class); // In nested UnitOfWork session might have been session of the parent. cursor.setSession(unitOfWork); result = cursor.getObjectCollection(); // for later incremental conforming... cursor.setInitiallyConformingIndex(indexedInterimResult); cursor.setSelectionCriteriaClone(getSelectionCriteria()); cursor.setTranslationRow(arguments); } // Now conform the result from the database. // Remove any deleted or changed objects that no longer conform. // Deletes will only work for simple queries, queries with or's or anyof's may not return // correct results when untriggered indirection is in the model. List fromDatabase = null; // When building directly from rows, one of the performance benefits // is that we no longer have to wrap and then unwrap the originals. // result is just a vector, not a container of wrapped originals. if (buildDirectlyFromRows) { List rows = (List)result; int size = rows.size(); fromDatabase = new ArrayList(size); for (int index = 0; index < size; index++) { AbstractRecord row = rows.get(index); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (row != null) { Object clone = conformIndividualResult(buildObject(row), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult); if (clone != null) { fromDatabase.add(clone); } } } } else { fromDatabase = new ArrayList(cp.sizeFor(result)); AbstractSession sessionToUse = unitOfWork.getParent(); for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) { Object object = cp.next(iter, sessionToUse); Object clone = conformIndividualResult(registerIndividualResult(object, null, unitOfWork, null, null), unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult); if (clone != null) { fromDatabase.add(clone); } } } // Now add the unwrapped conforming instances into an appropriate container. // Wrapping is done automatically. // Make sure a vector of exactly the right size is returned. Object conformedResult = cp.containerInstance(indexedInterimResult.size() + fromDatabase.size()); for (Iterator enumtr = indexedInterimResult.values().iterator(); enumtr.hasNext();) { Object eachClone = enumtr.next(); cp.addInto(eachClone, conformedResult, unitOfWork); } int size = fromDatabase.size(); for (int index = 0; index < size; index++) { Object eachClone = fromDatabase.get(index); cp.addInto(eachClone, conformedResult, unitOfWork); } if (cursor != null) { cursor.setObjectCollection((List)conformedResult); // For nested UOW must copy all in object collection to // initiallyConformingIndex, as some of these could have been from // the parent UnitOfWork. if (unitOfWork.isNestedUnitOfWork()) { for (Object clone : cursor.getObjectCollection()) { indexedInterimResult.put(clone, clone); } } return cursor; } else { return conformedResult; } } /** * INTERNAL: * Execute the query. If there are cached results return those. * This must override the super to support result caching. * * @param session - the session in which the receiver will be executed. * @return An object or vector, the result of executing the query. * @exception DatabaseException - an error has occurred on the database */ @Override public Object execute(AbstractSession session, AbstractRecord row) throws DatabaseException { if (shouldCacheQueryResults()) { if (getContainerPolicy().overridesRead()) { throw QueryException.cannotCacheCursorResultsOnQuery(this); } if (shouldConformResultsInUnitOfWork()) { throw QueryException.cannotConformAndCacheQueryResults(this); } if (isPrepared()) {// only prepared queries can have cached results. Object queryResults = getQueryResults(session, row, true); if (queryResults != null) { if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllHits(this); } session.incrementProfile(SessionProfiler.CacheHits, this); // bug6138532 - check for "cached no results" (InvalidObject singleton) in query // results, and return an empty container instance as configured if (queryResults == InvalidObject.instance) { return getContainerPolicy().containerInstance(0); } Collection results = (Collection)queryResults; if (session.isUnitOfWork()) { ContainerPolicy policy = getContainerPolicy(); Object resultCollection = policy.containerInstance(results.size()); Object iterator = policy.iteratorFor(results); while (policy.hasNext(iterator)) { Object result = ((UnitOfWorkImpl)session).registerExistingObject(policy.next(iterator, session), this.descriptor, null, true); policy.addInto(result, resultCollection, session); } return resultCollection; } return results; } } session.incrementProfile(SessionProfiler.CacheMisses, this); } if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllMisses(this); } return super.execute(session, row); } /** * INTERNAL: * Execute the query. * Get the rows and build the object from the rows. * @exception DatabaseException - an error has occurred on the database * @return java.lang.Object collection of objects resulting from execution of query. */ @Override protected Object executeObjectLevelReadQuery() throws DatabaseException { Object result = null; if (this.containerPolicy.overridesRead()) { this.executionTime = System.currentTimeMillis(); return this.containerPolicy.execute(); } if (this.descriptor.isDescriptorForInterface()) { Object returnValue = this.descriptor.getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this); this.executionTime = System.currentTimeMillis(); return returnValue; } if (this.descriptor.hasTablePerClassPolicy() && this.descriptor.isAbstract()) { result = this.containerPolicy.containerInstance(); } else { List rows = getQueryMechanism().selectAllRows(); this.executionTime = System.currentTimeMillis(); // If using 1-m joins, must set all rows. if (hasJoining() && this.joinedAttributeManager.isToManyJoin()) { this.joinedAttributeManager.setDataResults(rows, this.session); } // Batch fetching in IN requires access to the rows to build the id array. if ((this.batchFetchPolicy != null) && this.batchFetchPolicy.isIN()) { this.batchFetchPolicy.setDataResults(rows); } if (this.session.isUnitOfWork()) { result = registerResultInUnitOfWork(rows, (UnitOfWorkImpl)this.session, this.translationRow, true);// } else { result = this.containerPolicy.containerInstance(rows.size()); this.descriptor.getObjectBuilder().buildObjectsInto(this, rows, result); } if (this.shouldIncludeData) { ComplexQueryResult complexResult = new ComplexQueryResult(); complexResult.setResult(result); complexResult.setData(rows); result = complexResult; } } // Add the other (already registered) results and return them. if (this.descriptor.hasTablePerClassPolicy()) { result = this.containerPolicy.concatenateContainers( result, this.descriptor.getTablePerClassPolicy().selectAllObjectsUsingMultipleTableSubclassRead(this), this.session); } // If the results were empty, then ensure they get cached still. if (shouldCacheQueryResults() && this.containerPolicy.isEmpty(result)) { this.temporaryCachedQueryResults = InvalidObject.instance(); } return result; } /** * INTERNAL: * Execute the query building the objects directly from the database result-set. * @exception DatabaseException - an error has occurred on the database * @return an ArrayList of the resulting objects. */ @Override protected Object executeObjectLevelReadQueryFromResultSet() throws DatabaseException { AbstractSession session = this.session; DatabasePlatform platform = session.getPlatform(); DatabaseCall call = (DatabaseCall)((CallQueryMechanism)this.queryMechanism).getCall(); call.returnCursor(); call = this.queryMechanism.cursorSelectAllRows(); Statement statement = call.getStatement(); ResultSet resultSet = call.getResult(); DatabaseAccessor accessor = (DatabaseAccessor)((List)this.accessors).get(0); boolean exceptionOccured = false; try { ResultSetMetaData metaData = resultSet.getMetaData(); List results = new ArrayList(); ObjectBuilder builder = this.descriptor.getObjectBuilder(); while (resultSet.next()) { results.add(builder.buildObjectFromResultSet(this, this.joinedAttributeManager, resultSet, session, accessor, metaData, platform)); } return results; } catch (SQLException exception) { exceptionOccured = true; DatabaseException commException = accessor.processExceptionForCommError(session, exception, call); if (commException != null) { throw commException; } throw DatabaseException.sqlException(exception, call, accessor, session, false); } finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { accessor.releaseStatement(statement, call.getSQLString(), call, session); } if (accessor != null) { session.releaseReadConnection(accessor); } } catch (SQLException exception) { if (!exceptionOccured) { //in the case of an external connection pool the connection may be null after the statement release // if it is null we will be unable to check the connection for a comm error and //therefore must return as if it was not a comm error. DatabaseException commException = accessor.processExceptionForCommError(session, exception, call); if (commException != null) { throw commException; } throw DatabaseException.sqlException(exception, call, accessor, session, false); } } } } /** * INTERNAL: * Extract the correct query result from the transporter. */ @Override public Object extractRemoteResult(Transporter transporter) { return ((RemoteSession)getSession()).getObjectsCorrespondingToAll(transporter.getObject(), transporter.getObjectDescriptors(), new IdentityHashMap(), this, getContainerPolicy()); } /** * INTERNAL: * Return the query's container policy. */ public ContainerPolicy getContainerPolicy() { return containerPolicy; } /** * INTERNAL: * Returns the specific default redirector for this query type. There are numerous default query redirectors. * See ClassDescriptor for their types. */ @Override protected QueryRedirector getDefaultRedirector() { return descriptor.getDefaultReadAllQueryRedirector(); } /** * PUBLIC: * @return Expression - the start with expression used to generated the hierarchical query clause in * Oracle */ public Expression getStartWithExpression() { return startWithExpression; } /** * PUBLIC: * @return Expression - the connect by expression used to generate the hierarchical query caluse in Oracle */ public Expression getConnectByExpression() { return connectByExpression; } /** * PUBLIC: * @return List - the ordering expressions used to generate the hierarchical query clause in Oracle */ public List getOrderSiblingsByExpressions() { return orderSiblingsByExpressions; } /** * INTERNAL: * Verify that we have hierarchical query expressions */ public boolean hasHierarchicalExpressions() { return ((this.startWithExpression != null) || (this.connectByExpression != null) || (this.orderSiblingsByExpressions != null)); } /** * INTERNAL: * Return true if the query uses default properties. * This is used to determine if this query is cacheable. * i.e. does not use any properties that may conflict with another query * with the same JPQL or selection criteria. */ @Override public boolean isDefaultPropertiesQuery() { return super.isDefaultPropertiesQuery() && (!hasBatchReadAttributes()) && (!hasHierarchicalExpressions()) && (!this.containerPolicy.isCursorPolicy()); } /** * INTERNAL: * Return if the query is equal to the other. * This is used to allow dynamic expression query SQL to be cached. */ @Override public boolean equals(Object object) { if (this == object) { return true; } if (!super.equals(object)) { return false; } ReadAllQuery query = (ReadAllQuery) object; if (!this.containerPolicy.equals(query.containerPolicy)) { return false; } return true; } /** * PUBLIC: * Return if this is a read all query. */ @Override public boolean isReadAllQuery() { return true; } /** * INTERNAL: * Prepare the receiver for execution in a session. */ @Override protected void prepare() throws QueryException { if ((!isReportQuery()) && prepareFromCachedQuery()) { return; } super.prepare(); this.containerPolicy.prepare(this, getSession()); if (hasJoining() && isExpressionQuery()) { // 1-m join fetching with pagination requires an order by. if (this.joinedAttributeManager.isToManyJoin() && ((this.maxRows > 0) || (this.firstResult > 0) || this.containerPolicy.isCursorPolicy())) { if (!hasOrderByExpressions()) { for (DatabaseField primaryKey : this.descriptor.getPrimaryKeyFields()) { addOrdering(getExpressionBuilder().getField(primaryKey)); } } } } if (this.containerPolicy.overridesRead()) { return; } if (this.descriptor.isDescriptorForInterface()) { return; } prepareSelectAllRows(); } /** * INTERNAL: * Prepare the query from the prepared query. * This allows a dynamic query to prepare itself directly from a prepared query instance. * This is used in the JPQL parse cache to allow preparsed queries to be used to prepare * dynamic queries. * This only copies over properties that are configured through JPQL. */ @Override public void prepareFromQuery(DatabaseQuery query) { super.prepareFromQuery(query); if (query.isReadAllQuery()) { ReadAllQuery readQuery = (ReadAllQuery)query; this.containerPolicy = readQuery.containerPolicy; if (readQuery.hasHierarchicalExpressions()) { this.orderSiblingsByExpressions = readQuery.orderSiblingsByExpressions; this.connectByExpression = readQuery.connectByExpression; this.startWithExpression = readQuery.startWithExpression; } } } /** * INTERNAL: * Set the properties needed to be cascaded into the custom query. */ @Override protected void prepareCustomQuery(DatabaseQuery customQuery) { super.prepareCustomQuery(customQuery); ReadAllQuery customReadQuery = (ReadAllQuery)customQuery; customReadQuery.containerPolicy = this.containerPolicy; customReadQuery.cascadePolicy = this.cascadePolicy; customReadQuery.shouldRefreshIdentityMapResult = this.shouldRefreshIdentityMapResult; customReadQuery.shouldMaintainCache = this.shouldMaintainCache; customReadQuery.shouldUseWrapperPolicy = this.shouldUseWrapperPolicy; } /** * INTERNAL: * Prepare the receiver for execution in a session. */ @Override public void prepareForExecution() throws QueryException { super.prepareForExecution(); this.containerPolicy.prepareForExecution(); // Modifying the translation row here will modify it on the original // query which is not good. So we have to clone the translation row if // we are going to append tenant discriminator fields to it. if (descriptor.hasMultitenantPolicy()) { translationRow = translationRow.clone(); descriptor.getMultitenantPolicy().addFieldsToRow(translationRow, getSession()); } } /** * INTERNAL: * Prepare the mechanism. */ protected void prepareSelectAllRows() { getQueryMechanism().prepareSelectAllRows(); } /** * INTERNAL: * All objects queried via a UnitOfWork get registered here. If the query * went to the database. *

* Involves registering the query result individually and in totality, and * hence refreshing / conforming is done here. * * @param result may be collection (read all) or an object (read one), * or even a cursor. If in transaction the shared cache will * be bypassed, meaning the result may not be originals from the parent * but raw database rows. * @param unitOfWork the unitOfWork the result is being registered in. * @param arguments the original arguments/parameters passed to the query * execution. Used by conforming * @param buildDirectlyFromRows If in transaction must construct * a registered result from raw database rows. * * @return the final (conformed, refreshed, wrapped) UnitOfWork query result */ @Override public Object registerResultInUnitOfWork(Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) { // For bug 2612366: Conforming results in UOW extremely slow. // Replacing results with registered versions in the UOW is a part of // conforming and is now done while conforming to maximize performance. if (unitOfWork.hasCloneMapping() // PERF: Avoid conforming empty uow. && (shouldConformResultsInUnitOfWork() || this.descriptor.shouldAlwaysConformResultsInUnitOfWork())) { return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows); } // When building directly from rows, one of the performance benefits // is that we no longer have to wrap and then unwrap the originals. // result is just a vector, not a collection of wrapped originals. // Also for cursors the initial connection is automatically registered. if (buildDirectlyFromRows) { List rows = (List)result; ContainerPolicy cp = this.containerPolicy; int size = rows.size(); Object clones = cp.containerInstance(size); if(cp.shouldAddAll()) { List clonesIn = new ArrayList(size); List rowsIn = new ArrayList(size); for (int index = 0; index < size; index++) { AbstractRecord row = rows.get(index); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (row != null) { Object clone = buildObject(row); clonesIn.add(clone); rowsIn.add(row); } } cp.addAll(clonesIn, clones, unitOfWork, rowsIn, this, null, true); } else { if (this.descriptor.getCachePolicy().shouldPrefetchCacheKeys() && shouldMaintainCache() && ! shouldRetrieveBypassCache() && ((!(unitOfWork.hasCommitManager() && unitOfWork.getCommitManager().isActive()) && ! unitOfWork.wasTransactionBegunPrematurely() && !this.descriptor.getCachePolicy().shouldIsolateObjectsInUnitOfWork() && ! this.descriptor.getCachePolicy().shouldIsolateProtectedObjectsInUnitOfWork()) || (unitOfWork.isClassReadOnly(this.getReferenceClass(), this.getDescriptor())))){ Object[] pkList = new Object[size]; for (int i = 0; i< size; ++i){ pkList[i] = getDescriptor().getObjectBuilder().extractPrimaryKeyFromRow((AbstractRecord)rows.get(i), session); } setPrefetchedCacheKeys(unitOfWork.getParentIdentityMapSession(this).getIdentityMapAccessorInstance().getAllCacheKeysFromIdentityMapWithEntityPK(pkList, descriptor)); } for (int index = 0; index < size; index++) { AbstractRecord row = rows.get(index); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (row != null) { Object clone = buildObject(row); cp.addInto(clone, clones, unitOfWork, row, this, null, true); } } } return clones; } ContainerPolicy cp; Cursor cursor = null; // If the query is redirected then the collection returned might no longer // correspond to the original container policy. CR#2342-S.M. if (getRedirector() != null) { cp = ContainerPolicy.buildPolicyFor(result.getClass()); } else { cp = this.containerPolicy; } // In the case of cursors just register the initially read collection. if (cp.isCursorPolicy()) { cursor = (Cursor)result; // In nested UnitOfWork session might have been session of the parent. cursor.setSession(unitOfWork); cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class); result = cursor.getObjectCollection(); } Object clones = cp.containerInstance(cp.sizeFor(result)); AbstractSession sessionToUse = unitOfWork.getParent(); for (Object iter = cp.iteratorFor(result); cp.hasNext(iter);) { Object object = cp.next(iter, sessionToUse); Object clone = registerIndividualResult(object, null, unitOfWork, this.joinedAttributeManager, null); cp.addInto(clone, clones, unitOfWork); } if (cursor != null) { cursor.setObjectCollection((Vector)clones); return cursor; } else { return clones; } } /** * INTERNAL: * Execute the query through remote session. */ @Override public Object remoteExecute() { if (this.containerPolicy.overridesRead()) { return this.containerPolicy.remoteExecute(); } Object cacheHit = checkEarlyReturn(this.session, this.translationRow); if (cacheHit != null) { return cacheHit; } return super.remoteExecute(); } /** * INTERNAL: * replace the value holders in the specified result object(s) */ @Override public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) { return controller.replaceValueHoldersInAll(object, getContainerPolicy()); } /** * PUBLIC: * Set the container policy. Used to support different containers * (e.g. Collections, Maps). */ public void setContainerPolicy(ContainerPolicy containerPolicy) { // CR#... a container policy is always required, default is vector, // required for deployment XML. if (containerPolicy == null) { return; } this.containerPolicy = containerPolicy; setIsPrepared(false); } /** * PUBLIC: * Set the Hierarchical Query Clause for the query *

Example: *

Expression startWith = builder.get("id").equal(new Integer(100)); //can be any expression which identifies a set of employees *

Expression connectBy = builder.get("managedEmployees"); //indicated the relationship that the hierarchy is based on, must be self-referential *

Vector orderBy = new Vector(); *

orderBy.addElement(builder.get("startDate")); *

readAllQuery.setHierarchicalQueryClause(startWith, connectBy, orderBy); * *

This query would generate SQL like this: *

SELECT * FROM EMPLOYEE START WITH ID=100 CONNECT BY PRIOR ID = MANAGER_ID ORDER SIBLINGS BY START_DATE * * @param startWith Describes the START WITH clause of the query - null if not needed * @param connectBy This should be a query key expression which indicates an attribute who's mapping describes the hierarchy * @param orderSiblingsExpressions Contains expressions which indicate fields to be included in the ORDER SIBLINGS BY clause - null if not required */ public void setHierarchicalQueryClause(Expression startWith, Expression connectBy, List orderSiblingsExpressions) { this.startWithExpression = startWith; this.connectByExpression = connectBy; this.orderSiblingsByExpressions = orderSiblingsExpressions; setIsPrepared(false); } /** * PUBLIC: * Configure the mapping to use an instance of the specified container class * to hold the target objects. *

jdk1.2.x: The container class must implement (directly or indirectly) the Collection interface. *

jdk1.1.x: The container class must be a subclass of Vector. */ public void useCollectionClass(Class concreteClass) { // Set container policy. setContainerPolicy(ContainerPolicy.buildPolicyFor(concreteClass)); } /** * PUBLIC: * Use a CursoredStream as the result collection. * The initial read size is 10 and page size is 5. */ public void useCursoredStream() { useCursoredStream(10, 5); } /** * PUBLIC: * Use a CursoredStream as the result collection. * @param initialReadSize the initial number of objects to read * @param pageSize the number of objects to read when more objects * are needed from the database */ public void useCursoredStream(int initialReadSize, int pageSize) { setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize)); } /** * PUBLIC: * Use a CursoredStream as the result collection. * @param initialReadSize the initial number of objects to read * @param pageSize the number of objects to read when more objects * are needed from the database * @param sizeQuery a query that will return the size of the result set; * this must be set if an expression is not used (i.e. custom SQL) */ public void useCursoredStream(int initialReadSize, int pageSize, ValueReadQuery sizeQuery) { setContainerPolicy(new CursoredStreamPolicy(this, initialReadSize, pageSize, sizeQuery)); } /** * PUBLIC: * Configure the query to use an instance of the specified container class * to hold the result objects. The key used to index the value in the Map * is the value returned by a call to the specified zero-argument method. * The method must be implemented by the class (or a superclass) of the * value to be inserted into the Map. *

jdk1.2.x: The container class must implement (directly or indirectly) the Map interface. *

jdk1.1.x: The container class must be a subclass of Hashtable. *

The referenceClass must set before calling this method. */ public void useMapClass(Class concreteClass, String methodName) { // the reference class has to be specified before coming here if (getReferenceClass() == null) { throw QueryException.referenceClassMissing(this); } ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass); policy.setKeyName(methodName, getReferenceClass().getName()); setContainerPolicy(policy); } /** * PUBLIC: * Use a ScrollableCursor as the result collection. */ public void useScrollableCursor() { useScrollableCursor(10); } /** * PUBLIC: * Use a ScrollableCursor as the result collection. * @param pageSize the number of elements to be read into a the cursor * when more elements are needed from the database. */ public void useScrollableCursor(int pageSize) { setContainerPolicy(new ScrollableCursorPolicy(this, pageSize)); } /** * PUBLIC: * Use a ScrollableCursor as the result collection. * @param policy the scrollable cursor policy allows for additional result set options. * Example:

* ScrollableCursorPolicy policy = new ScrollableCursorPolicy()

* policy.setResultSetType(ScrollableCursorPolicy.TYPE_SCROLL_INSENSITIVE);

* query.useScrollableCursor(policy);

*/ public void useScrollableCursor(ScrollableCursorPolicy policy) { policy.setQuery(this); setContainerPolicy(policy); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy