FileDocCategorySizeDatePackage
ReadObjectQuery.javaAPI DocGlassfish v2 API27416Tue May 22 16:54:50 BST 2007oracle.toplink.essentials.queryframework

ReadObjectQuery

public class ReadObjectQuery extends ObjectLevelReadQuery

Purpose: Concrete class for all read queries involving a single object.

Responsibilities: Return a single object for the query. Implements the inheritance feature when dealing with abstract descriptors.

author
Yvon Lavoie
since
TOPLink/Java 1.0

Fields Summary
protected transient Object
selectionObject
Object that can be used in place of a selection criteria.
protected Vector
selectionKey
Key that can be used in place of a selection criteria.
protected boolean
shouldLoadResultIntoSelectionObject
Can be used to refresh a specific non-cached instance from the database.
Constructors Summary
public ReadObjectQuery()
PUBLIC: Return a new read object query. A reference class must be specified before execution. It is better to provide the class and expression builder on construction to esnure a single expression builder is used. If no selection criteria is specified this will reads the first object found in the database.


                                                            
      
        super();
    
public ReadObjectQuery(Class classToRead)
PUBLIC: Return a new read object query. By default, the query has no selection criteria. Executing this query without selection criteria will always result in a database access to read the first instance of the specified Class found in the database. This is true no matter how cache usage is configured and even if an instance of the specified Class exists in the cache. Executing a query with selection criteria allows you to avoid a database access if the selected instance is in the cache. For this reason, you may whish to use a ReadObjectQuery constructor that takes selection criteria, such as: {@link #ReadObjectQuery(Class, Call)}, {@link #ReadObjectQuery(Class, Expression)}, {@link #ReadObjectQuery(Class, ExpressionBuilder)}, {@link #ReadObjectQuery(ExpressionBuilder)}, {@link #ReadObjectQuery(Object)}, or {@link #ReadObjectQuery(Object, QueryByExamplePolicy)}.

        this();
        setReferenceClass(classToRead);
    
public ReadObjectQuery(Class classToRead, Expression selectionCriteria)
PUBLIC: Return a new read object query for the class and the selection criteria.

        this();
        setReferenceClass(classToRead);
        setSelectionCriteria(selectionCriteria);
    
public ReadObjectQuery(Class classToRead, ExpressionBuilder builder)
PUBLIC: Return a new read object query for the class. The expression builder must be used for all associated expressions used with the query.

        this();
        this.defaultBuilder = builder;
        setReferenceClass(classToRead);
    
public ReadObjectQuery(Class classToRead, Call call)
PUBLIC: Return a new read object query. The call represents a database interaction such as SQL, Stored Procedure.

        this();
        setReferenceClass(classToRead);
        setCall(call);
    
public ReadObjectQuery(Call call)
PUBLIC: Return a new read object query. The call represents a database interaction such as SQL, Stored Procedure.

        this();
        setCall(call);
    
public ReadObjectQuery(Object objectToRead)
PUBLIC: Return a query to read the object with the same primary key as the provided object. Note: This is not a query by example object, only the primary key will be used for the selection criteria.

        this();
        setSelectionObject(objectToRead);
    
public ReadObjectQuery(ExpressionBuilder builder)
PUBLIC: The expression builder should be provide on creation to ensure only one is used.

        this();
        this.defaultBuilder = builder;
    
Methods Summary
public voidcheckCacheByExactPrimaryKey()
PUBLIC: The cache will be checked only if the query contains exactly the primary key. Queries can be configured to use the cache at several levels. Other caching option are available.

see
#setCacheUsage(int)

        setCacheUsage(CheckCacheByExactPrimaryKey);
    
public voidcheckCacheByPrimaryKey()
PUBLIC: This is the default, the cache will be checked only if the query contains the primary key. Queries can be configured to use the cache at several levels. Other caching option are available.

see
#setCacheUsage(int)

        setCacheUsage(CheckCacheByPrimaryKey);
    
public voidcheckCacheThenDatabase()
PUBLIC: The cache will be checked completely, then if the object is not found or the query too complex the database will be queried. Queries can be configured to use the cache at several levels. Other caching option are available.

see
#setCacheUsage(int)

        setCacheUsage(CheckCacheThenDatabase);
    
public voidcheckDescriptor(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Ensure that the descriptor has been set.

        if (getReferenceClass() == null) {
            throw QueryException.referenceClassMissing(this);
        }

        if (getDescriptor() == null) {
            ClassDescriptor referenceDescriptor;
            //Bug#3947714  In case getSelectionObject() is proxy            
            if (getSelectionObject() != null && session.getProject().hasProxyIndirection()) {
                referenceDescriptor = session.getDescriptor(getSelectionObject());            
            } else {
                referenceDescriptor = session.getDescriptor(getReferenceClass());                
            }
            if (referenceDescriptor == null) {
                throw QueryException.descriptorIsMissing(getReferenceClass(), this);
            }
            setDescriptor(referenceDescriptor);
        }
    
protected java.lang.ObjectcheckEarlyReturnImpl(oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow)
INTERNAL: The cache check is done before the prepare as a hit will not require the work to be done.

        // Do a cache lookup
        if (shouldMaintainCache() && (!shouldRefreshIdentityMapResult()) && (!(shouldCheckDescriptorForCacheUsage() && getDescriptor().shouldDisableCacheHits())) && (shouldCheckCache())) {
            Object cachedObject = getQueryMechanism().checkCacheForObject(translationRow, session);

            // Optimization: If find deleted object by exact primary
            // key expression or selection object/key just abort.
            if (cachedObject == InvalidObject.instance) {
                return cachedObject;
            }
            if (cachedObject != null) {
                if (shouldLoadResultIntoSelectionObject()) {
                    ObjectBuilder builder = getDescriptor().getObjectBuilder();
                    builder.copyInto(cachedObject, getSelectionObject());
                    //put this object into the cache.  This may cause some loss of identity
                    session.getIdentityMapAccessorInstance().putInIdentityMap(getSelectionObject());
                    cachedObject = getSelectionObject();
                }

                // check locking.  If clone has not been locked, do not early return cached object
                if (isLockQuery() && (session.isUnitOfWork() && !((UnitOfWorkImpl)session).isPessimisticLocked(cachedObject))) {
                    return null;
                }
            }
            if (shouldUseWrapperPolicy()) {
                cachedObject = getDescriptor().getObjectBuilder().wrapObject(cachedObject, session);
            }
            return cachedObject;
        } else {
            return null;
        }
    
protected oracle.toplink.essentials.queryframework.DatabaseQuerycheckForCustomQuery(oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow)
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.

        checkDescriptor(session);

        // check if user defined a custom query in the query manager
        if (!isUserDefined()) {
            if (isCallQuery()) {
                // this is a hand-coded (custom SQL, SDK etc.) call
                return null;
            }
            DescriptorQueryManager descriptorQueryManager = getDescriptor().getQueryManager();

            // By default all descriptors have a custom ("static") read-object query.
            // This allows the read-object query and SQL to be prepare once.
            if (descriptorQueryManager.hasReadObjectQuery()) {
                // If the query require special SQL generation or execution do not use the static read object query.
                // PERF: the read-object query should always be static to ensure no regeneration of SQL.
                if (getJoinedAttributeManager().hasJoinedAttributeExpressions() || hasPartialAttributeExpressions() || hasAsOfClause() || hasNonDefaultFetchGroup() || (!wasDefaultLockMode()) || (!shouldIgnoreBindAllParameters())) {
                    return null;
                }

                if ((getSelectionKey() != null) || (getSelectionObject() != null)) {// Must be primary key.
                    return descriptorQueryManager.getReadObjectQuery();
                }

                if (getSelectionCriteria() != null) {
                    AbstractRecord primaryKeyRow = getDescriptor().getObjectBuilder().extractPrimaryKeyRowFromExpression(getSelectionCriteria(), translationRow, session);

                    // Only execute the query if the selection criteria has the primary key fields set
                    if (primaryKeyRow != null) {
                        return descriptorQueryManager.getReadObjectQuery();
                    }
                }
            }
        }

        return null;
    
protected java.lang.ObjectconformResult(java.lang.Object result, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, boolean buildDirectlyFromRows)
INTERNAL: Conform the result in the UnitOfWork.

        // Note that if the object does not conform even though other objects might exist on the database null is returned.
        // Note that new objects is checked before the read is executed so does not have to be re-checked.
        // Must unwrap as the built object is always wrapped.
        // Note the object is unwrapped on the parent which it belongs to, as we
        // do not want to trigger a registration just yet.
        Object implementation = null;
        if (buildDirectlyFromRows) {
            implementation = result;
        } else {
            implementation = getDescriptor().getObjectBuilder().unwrapObject(result, unitOfWork.getParent());
        }

        Expression selectionCriteriaClone = null;
        if ((getSelectionCriteria() != null) && (getSelectionKey() == null) && (getSelectionObject() == null)) {
            selectionCriteriaClone = (Expression)getSelectionCriteria().clone();
            selectionCriteriaClone.getBuilder().setSession(unitOfWork.getRootSession(null));
            selectionCriteriaClone.getBuilder().setQueryClass(getReferenceClass());
        }

        Object clone = conformIndividualResult(implementation, unitOfWork, databaseRow, selectionCriteriaClone, null, buildDirectlyFromRows);
        if (clone == null) {
            return clone;
        }

        if (shouldUseWrapperPolicy()) {
            return getDescriptor().getObjectBuilder().wrapObject(clone, unitOfWork);
        } else {
            return clone;
        }
    
public voiddontLoadResultIntoSelectionObject()
PUBLIC: Do not refesh/load into the selection object, this is the default. This property allows for the selection object of the query to be refreshed or put into the TopLink cache. By default on a read or refresh the object in the cache is refreshed and returned or a new object is built from the database, in some cases such as EJB BMP it is desirable to refresh or load into the object passed into the read object query.

Note: This forces the selection object into the cache a replaces any existing object that may already be there, this is a strict violation of object identity and other objects can still be refering to the old object.

        setShouldLoadResultIntoSelectionObject(false);
    
protected java.lang.ObjectexecuteObjectLevelReadQuery()
INTERNAL: Execute the query. Do a cache lookup and build object from row if required.

exception
DatabaseException - an error has occurred on the database
return
object - the first object found or null if none.

        AbstractRecord row = null;

        // If using -m joins, must select all rows.
        if (getJoinedAttributeManager().isToManyJoin()) {
            List rows = getQueryMechanism().selectAllRows();
            if (rows.size() > 0) {
                row = (AbstractRecord)rows.get(0);
            }
            getJoinedAttributeManager().setDataResults(rows, getSession());
        } else {
            row = getQueryMechanism().selectOneRow();
        }
        setExecutionTime(System.currentTimeMillis());
        Object result = null;

        if (getSession().isUnitOfWork()) {
            result = registerResultInUnitOfWork(row, (UnitOfWorkImpl)getSession(), getTranslationRow(), true);
        } else {
            if (row != null) {
                result = buildObject(row);
            }
        }

        if (shouldIncludeData()) {
            ComplexQueryResult complexResult = new ComplexQueryResult();
            complexResult.setResult(result);
            complexResult.setData(row);
            return complexResult;
        }

        return result;
    
public java.util.VectorgetSelectionKey()
PUBLIC: The primary key can be specified if used instead of an expression or selection object. If composite the primary must be in the same order as defined in the descriptor.

        return selectionKey;

    
public java.lang.ObjectgetSelectionObject()
PUBLIC: Return the selection object of the query. This can be used instead of a where clause expression for single object primary key queries. The selection object given should have a primary key defined, this primary key will be used to query the database instance of the same object. This is a basic form of query by example where only the primary key is required, it can be used for simple query forms, or testing.

        return selectionObject;
    
protected booleanhasNonDefaultFetchGroup()
INTERNAL: Return if the query has an non-default fetch group defined for itself.

        return getDescriptor().hasFetchGroupManager() && ((this.getFetchGroup() != null) || (this.getFetchGroupName() != null) || (!this.shouldUseDefaultFetchGroup()));

    
public booleanisReadObjectQuery()
PUBLIC: Return if this is a read object query.

        return true;
    
public voidloadResultIntoSelectionObject()
PUBLIC: Allow for the selection object of the query to be refreshed or put into the TopLink cache. By default on a read or refresh the object in the cache is refreshed and returned or a new object is built from the database, in some cases such as EJB BMP it is desirable to refresh or load into the object passed into the read object query.

Note: This forces the selection object into the cache a replaces any existing object that may already be there, this is a strict violation of object identity and other objects can still be refering to the old object.

        setShouldLoadResultIntoSelectionObject(true);
    
protected voidprepare()
INTERNAL: Prepare the receiver for execution in a session.

        super.prepare();

        if ((getSelectionKey() != null) || (getSelectionObject() != null)) {
            // The expression is set in the prepare as params.
            setSelectionCriteria(getDescriptor().getObjectBuilder().getPrimaryKeyExpression());
            // For bug 2989998 the translation row is required to be set at this point.
            if (!shouldPrepare()) {
                if (getSelectionKey() != null) {
                    // Row must come from the key.
                    setTranslationRow(getDescriptor().getObjectBuilder().buildRowFromPrimaryKeyValues(getSelectionKey(), getSession()));
                } else {//(getSelectionObject() != null)
                    setTranslationRow(getDescriptor().getObjectBuilder().buildRowForTranslation(getSelectionObject(), getSession()));
                }
            }
        }

        // If using -m joining select all rows.
        if (getJoinedAttributeManager().isToManyJoin()) {
            getQueryMechanism().prepareSelectAllRows();
        } else {
            getQueryMechanism().prepareSelectOneRow();
        }
    
protected voidprepareCustomQuery(oracle.toplink.essentials.queryframework.DatabaseQuery customQuery)
INTERNAL: Set the properties needed to be cascaded into the custom query inlucding the translation row.

        ReadObjectQuery customReadQuery = (ReadObjectQuery)customQuery;
        customReadQuery.setShouldRefreshIdentityMapResult(shouldRefreshIdentityMapResult());
        customReadQuery.setCascadePolicy(getCascadePolicy());
        customReadQuery.setShouldMaintainCache(shouldMaintainCache());
        customReadQuery.setShouldUseWrapperPolicy(shouldUseWrapperPolicy());
        // CR... was missing some values, execution could cause infinite loop.
        customReadQuery.setQueryId(getQueryId());
        customReadQuery.setExecutionTime(getExecutionTime());
        customReadQuery.setShouldLoadResultIntoSelectionObject(shouldLoadResultIntoSelectionObject());
        AbstractRecord primaryKeyRow;
        if (getSelectionObject() != null) {
            // CR#... Must also set the selection object as may be loading into the object (refresh)
            customReadQuery.setSelectionObject(getSelectionObject());
            // The translation/primary key row will be set in prepareForExecution.
        } else if (getSelectionKey() != null) {
            customReadQuery.setSelectionKey(getSelectionKey());
        } else {
            // The primary key row must be used.
            primaryKeyRow = customQuery.getDescriptor().getObjectBuilder().extractPrimaryKeyRowFromExpression(getSelectionCriteria(), customQuery.getTranslationRow(), customReadQuery.getSession());
            customReadQuery.setTranslationRow(primaryKeyRow);
        }
    
public voidprepareForExecution()
INTERNAL: Prepare the receiver for execution in a session.

        super.prepareForExecution();

        // For bug 2989998 the translation row now sometimes set earlier in prepare.
        if (shouldPrepare()) {
            if (getSelectionKey() != null) {
                // Row must come from the key.
                setTranslationRow(getDescriptor().getObjectBuilder().buildRowFromPrimaryKeyValues(getSelectionKey(), getSession()));
            } else if (getSelectionObject() != null) {
                // The expression is set in the prepare as params.
                setTranslationRow(getDescriptor().getObjectBuilder().buildRowForTranslation(getSelectionObject(), getSession()));
            }
        }
    
public java.lang.ObjectregisterResultInUnitOfWork(java.lang.Object result, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.sessions.AbstractRecord arguments, boolean buildDirectlyFromRows)
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

        if (result == null) {
            return null;
        }
        if (shouldConformResultsInUnitOfWork() || getDescriptor().shouldAlwaysConformResultsInUnitOfWork()) {
            return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows);
        }

        Object clone = registerIndividualResult(result, unitOfWork, buildDirectlyFromRows, null);

        if (shouldUseWrapperPolicy()) {
            clone = getDescriptor().getObjectBuilder().wrapObject(clone, unitOfWork);
        }
        return clone;
    
public voidsetSelectionKey(java.util.Vector selectionKey)
PUBLIC: The primary key can be specified if used instead of an expression or selection object. If composite the primary must be in the same order as defined in the descriptor.

        this.selectionKey = selectionKey;
        setIsPrepared(false);
    
public voidsetSelectionObject(java.lang.Object selectionObject)
PUBLIC: Used to set the where clause of the query. This can be used instead of a where clause expression for single object primary key queries. The selection object given should have a primary key defined, this primary key will be used to query the database instance of the same object. This is a basic form of query by example where only the primary key is required, it can be used for simple query forms, or testing.

        if (selectionObject == null) {
            throw QueryException.selectionObjectCannotBeNull(this);
        }
        setSelectionKey(null);
        // setIsPrepared(false) triggered by previous.
        setReferenceClass(selectionObject.getClass());
        this.selectionObject = selectionObject;
    
public voidsetShouldLoadResultIntoSelectionObject(boolean shouldLoadResultIntoSelectionObject)
PUBLIC: Allow for the selection object of the query to be refreshed or put into the TopLink cache. By default on a read or refresh the object in the cache is refreshed and returned or a new object is built from the database, in some cases such as EJB BMP it is desirable to refresh or load into the object passed into the read object query.

Note: This forces the selection object into the cache a replaces any existing object that may already be there, this is a strict violation of object identity and other objects can still be refering to the old object.

        this.shouldLoadResultIntoSelectionObject = shouldLoadResultIntoSelectionObject;
    
public voidsetSingletonSelectionKey(java.lang.Object selectionKey)
PUBLIC: The primary key can be specified if used instead of an expression or selection object.

        Vector key = new Vector();
        key.addElement(selectionKey);
        setSelectionKey(key);

    
public booleanshouldCheckCache()
PUBLIC: Return if the cache should be checked.

        return getCacheUsage() != DoNotCheckCache;
    
public booleanshouldCheckCacheByExactPrimaryKey()
PUBLIC: Return if cache should be checked.

        return getCacheUsage() == CheckCacheByExactPrimaryKey;
    
public booleanshouldCheckCacheByPrimaryKey()
PUBLIC: Return if cache should be checked.

        return (getCacheUsage() == CheckCacheByPrimaryKey) || (getCacheUsage() == UseDescriptorSetting);
    
public booleanshouldCheckCacheThenDatabase()
PUBLIC: Return if cache should be checked.

        return getCacheUsage() == CheckCacheThenDatabase;
    
public booleanshouldLoadResultIntoSelectionObject()
PUBLIC: return true if the result should be loaded into the passed in selection Object

        return shouldLoadResultIntoSelectionObject;