FileDocCategorySizeDatePackage
OneToOneMapping.javaAPI DocGlassfish v2 API55544Tue May 22 16:54:46 BST 2007oracle.toplink.essentials.mappings

OneToOneMapping

public class OneToOneMapping extends ObjectReferenceMapping implements RelationalMapping

Purpose: One to one mappings are used to represent a pointer references between two java objects. This mappings is usually represented by a single pointer (stored in an instance variable) between the source and target objects. In the relational database tables, these mappings are normally implemented using foreign keys.

author
Sati
since
TOPLink/Java 1.0

Fields Summary
protected Map
sourceToTargetKeyFields
Maps the source foreign/primary key fields to the target primary/foreign key fields.
protected Map
targetToSourceKeyFields
Maps the target primary/foreign key fields to the source foreign/primary key fields.
protected boolean
shouldVerifyDelete
These are used for non-unit of work modification to check if the value of the 1-1 was changed and a deletion is required.
protected transient Expression
privateOwnedCriteria
protected boolean
usesJoining
Indicates whether the referenced object should always be joined on read queries.
Constructors Summary
public OneToOneMapping()
PUBLIC: Default constructor.

        this.selectionQuery = new ReadObjectQuery();
        this.sourceToTargetKeyFields = new HashMap(2);
        this.targetToSourceKeyFields = new HashMap(2);
        this.foreignKeyFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1);
        this.isForeignKeyRelationship = false;
        this.shouldVerifyDelete = true;
        this.usesJoining = false;
    
Methods Summary
public voidaddForeignKeyField(DatabaseField sourceForeignKeyField, DatabaseField targetPrimaryKeyField)
PUBLIC: Define the foreign key relationship in the 1-1 mapping. This method is used for composite foreign key relationships, that is the source object's table has multiple foreign key fields to the target object's primary key fields. Both the source foreign key field and the target foreign key field must be specified. When a foreign key is specified TopLink will automatically populate the value for that field from the target object when the object is written to the database. If the foreign key is also mapped through a direct-to-field then the direct-to-field must be set read-only.

        setIsForeignKeyRelationship(true);
        getForeignKeyFields().addElement(sourceForeignKeyField);

        getSourceToTargetKeyFields().put(sourceForeignKeyField, targetPrimaryKeyField);
        getTargetToSourceKeyFields().put(targetPrimaryKeyField, sourceForeignKeyField);
    
public voidaddForeignKeyFieldName(java.lang.String sourceForeignKeyFieldName, java.lang.String targetPrimaryKeyFieldName)
PUBLIC: Define the foreign key relationship in the 1-1 mapping. This method is used for composite foreign key relationships, that is the source object's table has multiple foreign key fields to the target object's primary key fields. Both the source foreign key field name and the target foreign key field name must be specified. When a foreign key is specified TopLink will automatically populate the value for that field from the target object when the object is written to the database. If the foreign key is also mapped through a direct-to-field then the direct-to-field must be set read-only.

        addForeignKeyField(new DatabaseField(sourceForeignKeyFieldName), new DatabaseField(targetPrimaryKeyFieldName));
    
public voidaddTargetForeignKeyField(DatabaseField targetForeignKeyField, DatabaseField sourcePrimaryKeyField)
PUBLIC: Define the target foreign key relationship in the 1-1 mapping. This method is used for composite target foreign key relationships, that is the target object's table has multiple foreign key fields to the source object's primary key fields. Both the target foreign key field and the source primary key field must be specified. The distinction between a foreign key and target foreign key is that the 1-1 mapping will not populate the target foreign key value when written (because it is in the target table). Normally 1-1's are through foreign keys but in bi-directional 1-1's the back reference will be a target foreign key. In obscure composite legacy data models a 1-1 may consist of a foreign key part and a target foreign key part, in this case both method will be called with the correct parts.

        getSourceToTargetKeyFields().put(sourcePrimaryKeyField, targetForeignKeyField);
        getTargetToSourceKeyFields().put(targetForeignKeyField, sourcePrimaryKeyField);
    
public voidaddTargetForeignKeyFieldName(java.lang.String targetForeignKeyFieldName, java.lang.String sourcePrimaryKeyFieldName)
PUBLIC: Define the target foreign key relationship in the 1-1 mapping. This method is used for composite target foreign key relationships, that is the target object's table has multiple foreign key fields to the source object's primary key fields. Both the target foreign key field name and the source primary key field name must be specified. The distinction between a foreign key and target foreign key is that the 1-1 mapping will not populate the target foreign key value when written (because it is in the target table). Normally 1-1's are through foreign keys but in bi-directional 1-1's the back reference will be a target foreign key. In obscure composite legacy data models a 1-1 may consist of a foreign key part and a target foreign key part, in this case both method will be called with the correct parts.

        addTargetForeignKeyField(new DatabaseField(targetForeignKeyFieldName), new DatabaseField(sourcePrimaryKeyFieldName));
    
public ExpressionbuildObjectJoinExpression(Expression expression, java.lang.Object value, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used to allow object level comparisons.

        Expression base = ((oracle.toplink.essentials.internal.expressions.ObjectExpression)expression).getBaseExpression();
        Expression foreignKeyJoin = null;

        // Allow for equal null.
        if (value == null) {
            // Can only perform null comparison on foreign key relationships.
            // It does not really make sense for target any way as it is the source key.
            if (!isForeignKeyRelationship()) {
                throw QueryException.cannotCompareTargetForeignKeysToNull(base, value, this);
            }
            for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
                     sourceFieldsEnum.hasNext();) {
                DatabaseField field = (DatabaseField)sourceFieldsEnum.next();
                Expression join = null;
                if (expression.isObjectExpression() && ((ObjectExpression)expression).shouldUseOuterJoin()){
                    join = base.getField(field).equalOuterJoin(null);
                } else {
                    join = base.getField(field).equal(null);
                }
                if (foreignKeyJoin == null) {
                    foreignKeyJoin = join;
                } else {
                    foreignKeyJoin = foreignKeyJoin.and(join);
                }
            }
        } else {
            if (!getReferenceDescriptor().getJavaClass().isInstance(value)) {
                throw QueryException.incorrectClassForObjectComparison(base, value, this);
            }

            Enumeration keyEnum = extractKeyFromReferenceObject(value, session).elements();
            for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
                     sourceFieldsEnum.hasNext();) {
                DatabaseField field = (DatabaseField)sourceFieldsEnum.next();
                Expression join = null;
                if (expression.isObjectExpression() && ((ObjectExpression)expression).shouldUseOuterJoin()){
                    join = base.getField(field).equalOuterJoin(keyEnum.nextElement());
                } else {
                    join = base.getField(field).equal(keyEnum.nextElement());
                }
                if (foreignKeyJoin == null) {
                    foreignKeyJoin = join;
                } else {
                    foreignKeyJoin = foreignKeyJoin.and(join);
                }
            }
        }
        return foreignKeyJoin;
    
public ExpressionbuildObjectJoinExpression(Expression expression, Expression argument, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used to allow object level comparisons.

        Expression base = ((oracle.toplink.essentials.internal.expressions.ObjectExpression)expression).getBaseExpression();
        Expression foreignKeyJoin = null;
        if (expression==argument){
            for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
                     sourceFieldsEnum.hasNext();) {
                DatabaseField field = (DatabaseField)sourceFieldsEnum.next();
                Expression join = base.getField(field);
                if (expression.isObjectExpression() && ((ObjectExpression)expression).shouldUseOuterJoin()){
                    join = join.equalOuterJoin(join);
                } else {
                    join = join.equal(join);
                }
                if (foreignKeyJoin == null) {
                    foreignKeyJoin = join;
                } else {
                    foreignKeyJoin = foreignKeyJoin.and(join);
                }
            }
        }else{
            Iterator targetFieldsEnum = getSourceToTargetKeyFields().values().iterator();
            for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
                     sourceFieldsEnum.hasNext();) {
                DatabaseField sourceField = (DatabaseField)sourceFieldsEnum.next();
                DatabaseField targetField = (DatabaseField)targetFieldsEnum.next();
                Expression join = null;
                if (expression.isObjectExpression() && ((ObjectExpression)expression).shouldUseOuterJoin()){
                    join = base.getField(sourceField).equalOuterJoin(argument.getField(targetField));
                } else {
                    join = base.getField(sourceField).equal(argument.getField(targetField));
                }
                if (foreignKeyJoin == null) {
                    foreignKeyJoin = join;
                } else {
                    foreignKeyJoin = foreignKeyJoin.and(join);
                }
            }
        }
        return foreignKeyJoin;
    
public ExpressionbuildSelectionCriteria()
This method would allow customers to get the potential selection criteria for a mapping prior to initialization. This would allow them to more easily create an ammendment method that would ammend the SQL for the join. CR#3922 - This method is almost the same as initializeSelectionCriteria() the difference is that getSelectionCriteria() is not called

        // CR3922
        if (getSourceToTargetKeyFields().isEmpty()) {
            throw DescriptorException.noForeignKeysAreSpecified(this);
        }

        Expression criteria = null;
        Expression builder = new ExpressionBuilder();

        for (Iterator keys = getSourceToTargetKeyFields().keySet().iterator(); keys.hasNext();) {
            DatabaseField foreignKey = (DatabaseField)keys.next();
            DatabaseField targetKey = (DatabaseField)getSourceToTargetKeyFields().get(foreignKey);

            Expression expression = builder.getField(targetKey).equal(builder.getParameter(foreignKey));
            if (criteria == null) {
                criteria = expression;
            } else {
                criteria = expression.and(criteria);
            }
        }
        return criteria;
    
public voidbuildShallowOriginalFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, java.lang.Object original, ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractSession executionSession)
INTERNAL: Builds a shallow original object. Only direct attributes and primary keys are populated. In this way the minimum original required for instantiating a working copy clone can be built without placing it in the shared cache (no concern over cycles).

        // Now we are only building this original so we can extract the primary
        // key out of it.  If the primary key is stored accross a 1-1 a value
        // holder needs to be built/triggered to get at it.
        // In this case recursively build the shallow original accross the 1-1.
        // We only need the primary key for that object, and we know
        // what that primary key is: it is the foreign key in our row.
        ClassDescriptor descriptor = getReferenceDescriptor();
        AbstractRecord targetRow = new DatabaseRecord();

        for (Iterator keys = getSourceToTargetKeyFields().keySet().iterator(); keys.hasNext();) {
            DatabaseField foreignKey = (DatabaseField)keys.next();
            DatabaseField targetKey = (DatabaseField)getSourceToTargetKeyFields().get(foreignKey);

            targetRow.put(targetKey, databaseRow.get(foreignKey));
        }

        Object targetObject = descriptor.getObjectBuilder().buildNewInstance();
        descriptor.getObjectBuilder().buildAttributesIntoShallowObject(targetObject, databaseRow, query);
        targetObject = getIndirectionPolicy().valueFromRow(targetObject);

        setAttributeValueInObject(original, targetObject);
    
public java.lang.Objectclone()
INTERNAL: This methods clones all the fields and ensures that each collection refers to the same clones.

        OneToOneMapping clone = (OneToOneMapping)super.clone();
        clone.setForeignKeyFields(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(getForeignKeyFields().size()));
        clone.setSourceToTargetKeyFields(new HashMap(getSourceToTargetKeyFields().size()));
        clone.setTargetToSourceKeyFields(new HashMap(getTargetToSourceKeyFields().size()));
        Hashtable setOfFields = new Hashtable(getTargetToSourceKeyFields().size());

        //clone foreign keys and save the clones in a set
        for (Enumeration enumtr = getForeignKeyFields().elements(); enumtr.hasMoreElements();) {
            DatabaseField field = (DatabaseField)enumtr.nextElement();
            DatabaseField fieldClone = (DatabaseField)field.clone();
            setOfFields.put(field, fieldClone);
            clone.getForeignKeyFields().addElement(fieldClone);
        }

        //get clones from set for source hashtable.  If they do not exist, create a new one.
        for (Iterator sourceEnum = getSourceToTargetKeyFields().keySet().iterator();
                 sourceEnum.hasNext();) {
            DatabaseField sourceField = (DatabaseField)sourceEnum.next();
            DatabaseField targetField = (DatabaseField)getSourceToTargetKeyFields().get(sourceField);

            DatabaseField targetClone;
            DatabaseField sourceClone;

            targetClone = (DatabaseField)setOfFields.get(targetField);
            if (targetClone == null) {
                targetClone = (DatabaseField)targetField.clone();
                setOfFields.put(targetField, targetClone);
            }
            sourceClone = (DatabaseField)setOfFields.get(sourceField);
            if (sourceClone == null) {
                sourceClone = (DatabaseField)sourceField.clone();
                setOfFields.put(sourceField, sourceClone);
            }
            clone.getSourceToTargetKeyFields().put(sourceClone, targetClone);
        }

        //get clones from set for target hashtable.  If they do not exist, create a new one.
        for (Iterator targetEnum = getTargetToSourceKeyFields().keySet().iterator();
                 targetEnum.hasNext();) {
            DatabaseField targetField = (DatabaseField)targetEnum.next();
            DatabaseField sourceField = (DatabaseField)getTargetToSourceKeyFields().get(targetField);

            DatabaseField targetClone;
            DatabaseField sourceClone;

            targetClone = (DatabaseField)setOfFields.get(targetField);
            if (targetClone == null) {
                targetClone = (DatabaseField)targetField.clone();
                setOfFields.put(targetField, targetClone);
            }
            sourceClone = (DatabaseField)setOfFields.get(sourceField);
            if (sourceClone == null) {
                sourceClone = (DatabaseField)sourceField.clone();
                setOfFields.put(sourceField, sourceClone);
            }
            clone.getTargetToSourceKeyFields().put(targetClone, sourceClone);
        }
        return clone;
    
public voiddontUseJoining()
PUBLIC: Indicates whether the referenced object should always be joined on read queries. Joining will join the two classes tables to read all of the data in a single query. This should only be used if it is know that the related objects are always required with the source object, or indirection is not used.

        setUsesJoining(false);
    
protected java.util.VectorextractForeignKeyFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the foreign key value from the source row.

        Vector key = new Vector();

        for (Iterator fieldEnum = getSourceToTargetKeyFields().keySet().iterator();
                 fieldEnum.hasNext();) {
            DatabaseField field = (DatabaseField)fieldEnum.next();
            Object value = row.get(field);

            // Must ensure the classificatin to get a cache hit.
            try {
                value = session.getDatasourcePlatform().getConversionManager().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(field));
            } catch (ConversionException e) {
                throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
            }

            key.addElement(value);
        }

        return key;
    
protected java.util.VectorextractKeyFromReferenceObject(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the key value from the reference object.

        Vector key = new Vector();

        for (Iterator fieldEnum = getSourceToTargetKeyFields().values().iterator();
                 fieldEnum.hasNext();) {
            DatabaseField field = (DatabaseField)fieldEnum.next();

            if (object == null) {
                key.addElement(null);
            } else {
                key.addElement(getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(object, field, session));
            }
        }

        return key;
    
public java.util.VectorextractPrimaryKeysForReferenceObjectFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row)
INTERNAL: Return the primary key for the reference object (i.e. the object object referenced by domainObject and specified by mapping). This key will be used by a RemoteValueHolder.

        List primaryKeyFields = getReferenceDescriptor().getPrimaryKeyFields();
        Vector result = new Vector(primaryKeyFields.size());
        for (int index = 0; index < primaryKeyFields.size(); index++) {
            DatabaseField targetKeyField = (DatabaseField)primaryKeyFields.get(index);
            DatabaseField sourceKeyField = (DatabaseField)getTargetToSourceKeyFields().get(targetKeyField);
            if (sourceKeyField == null) {
                return new Vector(1);
            }
            result.addElement(row.get(sourceKeyField));
        }
        return result;
    
public java.lang.ClassgetFieldClassification(DatabaseField fieldToClassify)
INTERNAL: Return the classifiction for the field contained in the mapping. This is used to convert the row value to a consistent java value.

        DatabaseField fieldInTarget = (DatabaseField)getSourceToTargetKeyFields().get(fieldToClassify);
        if (fieldInTarget == null) {
            return null;// Can be registered as multiple table secondary field mapping
        }
        DatabaseMapping mapping = getReferenceDescriptor().getObjectBuilder().getMappingForField(fieldInTarget);
        if (mapping == null) {
            return null;// Means that the mapping is read-only
        }
        return mapping.getFieldClassification(fieldInTarget);
    
public java.util.VectorgetForeignKeyFieldNames()
PUBLIC: Return the foreign key field names associated with the mapping. These are only the source fields that are writable.

        Vector fieldNames = new Vector(getForeignKeyFields().size());
        for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
        }

        return fieldNames;
    
protected java.util.MapgetForeignKeysToPrimaryKeys()
Return the appropriate hashtable that maps the "foreign keys" to the "primary keys".

        if (this.isForeignKeyRelationship()) {
            return this.getSourceToTargetKeyFields();
        } else {
            return this.getTargetToSourceKeyFields();
        }
    
public java.util.VectorgetOrderedForeignKeyFields()
INTERNAL: Return a vector of the foreign key fields in the same order as the corresponding primary key fields are in their descriptor.

        List primaryKeyFields = getPrimaryKeyDescriptor().getPrimaryKeyFields();
        Vector result = new Vector(primaryKeyFields.size());

        for (int index = 0; index < primaryKeyFields.size(); index++) {
            DatabaseField pkField = (DatabaseField)primaryKeyFields.get(index);
            boolean found = false;
            for (Iterator fkStream = this.getForeignKeysToPrimaryKeys().keySet().iterator();
                     fkStream.hasNext();) {
                DatabaseField fkField = (DatabaseField)fkStream.next();

                if (this.getForeignKeysToPrimaryKeys().get(fkField).equals(pkField)) {
                    found = true;
                    result.addElement(fkField);
                    break;
                }
            }
            if (!found) {
                throw DescriptorException.missingForeignKeyTranslation(this, pkField);
            }
        }
        return result;
    
protected oracle.toplink.essentials.descriptors.ClassDescriptorgetPrimaryKeyDescriptor()
Return the descriptor for whichever side of the relation has the "primary key".

        if (this.isForeignKeyRelationship()) {
            return this.getReferenceDescriptor();
        } else {
            return this.getDescriptor();
        }
    
public ExpressiongetPrivateOwnedCriteria()
INTERNAL: The private owned criteria is only used outside of the unit of work to compare the previous value of the reference.

        if (privateOwnedCriteria == null) {
            initializePrivateOwnedCriteria();
        }
        return privateOwnedCriteria;
    
public java.util.VectorgetSourceToTargetKeyFieldAssociations()
INTERNAL: Return a collection of the source to target field value associations.

        Vector associations = new Vector(getSourceToTargetKeyFields().size());
        Iterator sourceFieldEnum = getSourceToTargetKeyFields().keySet().iterator();
        Iterator targetFieldEnum = getSourceToTargetKeyFields().values().iterator();
        while (sourceFieldEnum.hasNext()) {
            Object fieldValue = ((DatabaseField)sourceFieldEnum.next()).getQualifiedName();
            Object attributeValue = ((DatabaseField)targetFieldEnum.next()).getQualifiedName();
            associations.addElement(new Association(fieldValue, attributeValue));
        }

        return associations;
    
public java.util.MapgetSourceToTargetKeyFields()
INTERNAL: Returns the source keys to target keys fields association.

        return sourceToTargetKeyFields;
    
public java.util.MapgetTargetToSourceKeyFields()
INTERNAL: Returns the target keys to source keys fields association.

        return targetToSourceKeyFields;
    
public voidinitialize(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Initialize the mapping.

        super.initialize(session);
        
        // Must set table of foreign keys.
        for (Enumeration foreignKeysEnum = getForeignKeyFields().elements();
                 foreignKeysEnum.hasMoreElements();) {
            DatabaseField foreignKeyField = (DatabaseField)foreignKeysEnum.nextElement();
            getDescriptor().buildField(foreignKeyField);
        }

        // If only a selection criteria is specified then the foreign keys do not have to be initialized.
        if (!(getTargetToSourceKeyFields().isEmpty() && getSourceToTargetKeyFields().isEmpty())) {
            if (getTargetToSourceKeyFields().isEmpty() || getSourceToTargetKeyFields().isEmpty()) {
                initializeForeignKeysWithDefaults(session);
            } else {
                initializeForeignKeys(session);
            }
        }

        if (shouldInitializeSelectionCriteria()) {
            initializeSelectionCriteria(session);
        } else {
            setShouldVerifyDelete(false);
        }

        setFields(collectFields());
    
protected voidinitializeForeignKeys(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: The foreign keys primary keys are stored as database fields in the hashtable.

        Iterator sourceEnum = getSourceToTargetKeyFields().keySet().iterator();
        Iterator targetEnum = getTargetToSourceKeyFields().keySet().iterator();
        while (sourceEnum.hasNext()) {
            DatabaseField sourceField = (DatabaseField)sourceEnum.next();
            DatabaseField targetField = (DatabaseField)targetEnum.next();

            getDescriptor().buildField(sourceField);
            getReferenceDescriptor().buildField(targetField);
        }
    
protected voidinitializeForeignKeysWithDefaults(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: The foreign keys primary keys are stored as database fields in the hashtable.

        if (isForeignKeyRelationship()) {
            if (getSourceToTargetKeyFields().size() != 1) {
                throw DescriptorException.foreignKeysDefinedIncorrectly(this);
            }
            List<DatabaseField> targetKeys = getReferenceDescriptor().getPrimaryKeyFields();
            if (targetKeys.size() != 1) {
                //target and source keys are not the same size.
                throw DescriptorException.sizeMismatchOfForeignKeys(this);
            }

            //grab the only element out of the Hashtable
            DatabaseField sourceField = (DatabaseField)getSourceToTargetKeyFields().keySet().iterator().next();
            getDescriptor().buildField(sourceField);
            getSourceToTargetKeyFields().put(sourceField, targetKeys.get(0));
            getTargetToSourceKeyFields().put(targetKeys.get(0), sourceField);
        } else {
            if (getTargetToSourceKeyFields().size() != 1) {
                throw DescriptorException.foreignKeysDefinedIncorrectly(this);
            }
            List<DatabaseField> sourceKeys = getDescriptor().getPrimaryKeyFields();
            if (sourceKeys.size() != 1) {
                //target and source keys are not the same size.
                throw DescriptorException.sizeMismatchOfForeignKeys(this);
            }

            //grab the only element out of the Hashtable
            DatabaseField targetField = (DatabaseField)getTargetToSourceKeyFields().keySet().iterator().next();
            getReferenceDescriptor().buildField(targetField);
            getTargetToSourceKeyFields().put(targetField, sourceKeys.get(0));
            getSourceToTargetKeyFields().put(sourceKeys.get(0), targetField);
        }
    
protected voidinitializePrivateOwnedCriteria()
INTERNAL: Selection criteria is created with source foreign keys and target keys.

        if (!isForeignKeyRelationship()) {
            setPrivateOwnedCriteria(getSelectionCriteria());
        } else {
            Expression pkCriteria = getDescriptor().getObjectBuilder().getPrimaryKeyExpression();
            ExpressionBuilder builder = new ExpressionBuilder();
            Expression backRef = builder.getManualQueryKey(getAttributeName() + "-back-ref", getDescriptor());
            Expression newPKCriteria = pkCriteria.rebuildOn(backRef);
            Expression twistedSelection = backRef.twist(getSelectionCriteria(), builder);
            if (getDescriptor().getQueryManager().getAdditionalJoinExpression() != null) {
                // We don't have to twist the additional join because it's all against the same node, which is our base
                // but we do have to rebuild it onto the manual query key
                Expression rebuiltAdditional = getDescriptor().getQueryManager().getAdditionalJoinExpression().rebuildOn(backRef);
                if (twistedSelection == null) {
                    twistedSelection = rebuiltAdditional;
                } else {
                    twistedSelection = twistedSelection.and(rebuiltAdditional);
                }
            }
            setPrivateOwnedCriteria(newPKCriteria.and(twistedSelection));
        }
    
protected voidinitializeSelectionCriteria(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Selection criteria is created with source foreign keys and target keys. This criteria is then used to read target records from the table. CR#3922 - This method is almost the same as buildSelectionCriteria() the difference is that getSelectionCriteria() is called

        if (getSourceToTargetKeyFields().isEmpty()) {
            throw DescriptorException.noForeignKeysAreSpecified(this);
        }

        Expression criteria;
        Expression builder = new ExpressionBuilder();
        for (Iterator entries = getSourceToTargetKeyFields().entrySet().iterator(); entries.hasNext();) {
            Map.Entry entry = (Map.Entry) entries.next();
            DatabaseField foreignKey = (DatabaseField)entry.getKey();
            DatabaseField targetKey = (DatabaseField)entry.getValue();
            Expression expression = builder.getField(targetKey).equal(builder.getParameter(foreignKey));
            criteria = expression.and(getSelectionCriteria());
            setSelectionCriteria(criteria);
        }
    
public booleanisCascadedLockingSupported()
INTERNAL Return true if this mapping supports cascaded version optimistic locking.

        return true;
    
public booleanisJoiningSupported()
INTERNAL: Return if this mapping support joining.

        return true;
    
public booleanisOneToOneMapping()
INTERNAL:

        return true;
    
public booleanisRelationalMapping()
INTERNAL:

        return true;
    
protected java.lang.ObjectreadPrivateOwnedForObject(ObjectLevelModifyQuery modifyQuery)
INTERNAL: Reads the private owned object.

        if (modifyQuery.getSession().isUnitOfWork()) {
            return super.readPrivateOwnedForObject(modifyQuery);
        } else {
            if (!shouldVerifyDelete()) {
                return null;
            }
            ReadObjectQuery readQuery = (ReadObjectQuery)getSelectionQuery().clone();

            readQuery.setSelectionCriteria(getPrivateOwnedCriteria());
            return modifyQuery.getSession().executeQuery(readQuery, modifyQuery.getTranslationRow());
        }
    
public voidrehashFieldDependancies(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Rehash any hashtables based on fields. This is used to clone descriptors for aggregates, which hammer field names, it is probably better not to hammer the field name and this should be refactored.

        setSourceToTargetKeyFields(Helper.rehashMap(getSourceToTargetKeyFields()));
    
public voidsetForeignKeyFieldName(java.lang.String sourceForeignKeyFieldName)
PUBLIC: Define the foreign key relationship in the 1-1 mapping. This method is used for singleton foreign key relationships only, that is the source object's table has a foreign key field to the target object's primary key field. Only the source foreign key field name is specified. When a foreign key is specified TopLink will automatically populate the value for that field from the target object when the object is written to the database. If the foreign key is also mapped through a direct-to-field then the direct-to-field must be set read-only.

        DatabaseField sourceField = new DatabaseField(sourceForeignKeyFieldName);

        setIsForeignKeyRelationship(true);
        getForeignKeyFields().addElement(sourceField);
        getSourceToTargetKeyFields().put(sourceField, new DatabaseField());
    
public voidsetForeignKeyFieldNames(java.util.Vector fieldNames)
PUBLIC: Return the foreign key field names associated with the mapping. These are only the source fields that are writable.

        Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
        for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
            fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
        }

        setForeignKeyFields(fields);
    
protected voidsetPrivateOwnedCriteria(Expression expression)
INTERNAL: Private owned criteria is used to verify the deletion of the target. It joins from the source table on the foreign key to the target table, with a parameterization of the primary key of the source object.

        privateOwnedCriteria = expression;
    
public voidsetShouldVerifyDelete(boolean shouldVerifyDelete)
PUBLIC: Verify delete is used during delete and update on private 1:1's outside of a unit of work only. It checks for the previous value of the target object through joining the source and target tables. By default it is always done, but may be disabled for performance on distributed database reasons. In the unit of work the previous value is obtained from the backup-clone so it is never used.

        this.shouldVerifyDelete = shouldVerifyDelete;
    
public voidsetSourceToTargetKeyFieldAssociations(java.util.Vector sourceToTargetKeyFieldAssociations)
INTERNAL: Set a collection of the source to target field associations.

        setSourceToTargetKeyFields(new HashMap(sourceToTargetKeyFieldAssociations.size() + 1));
        setTargetToSourceKeyFields(new HashMap(sourceToTargetKeyFieldAssociations.size() + 1));
        for (Enumeration associationsEnum = sourceToTargetKeyFieldAssociations.elements();
                 associationsEnum.hasMoreElements();) {
            Association association = (Association)associationsEnum.nextElement();
            DatabaseField sourceField = new DatabaseField((String)association.getKey());
            DatabaseField targetField = new DatabaseField((String)association.getValue());
            getSourceToTargetKeyFields().put(sourceField, targetField);
            getTargetToSourceKeyFields().put(targetField, sourceField);
        }
    
public voidsetSourceToTargetKeyFields(java.util.Map sourceToTargetKeyFields)
INTERNAL: Set the source keys to target keys fields association.

        this.sourceToTargetKeyFields = sourceToTargetKeyFields;
    
public voidsetTargetForeignKeyFieldName(java.lang.String targetForeignKeyFieldName)
PUBLIC: Define the target foreign key relationship in the 1-1 mapping. This method is used for singleton target foreign key relationships only, that is the target object's table has a foreign key field to the source object's primary key field. The target foreign key field name is specified. The distinction between a foreign key and target foreign key is that the 1-1 mapping will not populate the target foreign key value when written (because it is in the target table). Normally 1-1's are through foreign keys but in bi-directional 1-1's the back reference will be a target foreign key.

        DatabaseField targetField = new DatabaseField(targetForeignKeyFieldName);
        getTargetToSourceKeyFields().put(targetField, new DatabaseField());
    
public voidsetTargetToSourceKeyFields(java.util.Map targetToSourceKeyFields)
INTERNAL: Set the target keys to source keys fields association.

        this.targetToSourceKeyFields = targetToSourceKeyFields;
    
public voidsetUsesJoining(boolean usesJoining)
PUBLIC: Indicates whether the referenced object should always be joined on read queries. Joining will join the two classes tables to read all of the data in a single query. This should only be used if it is know that the related objects are always required with the source object, or indirection is not used.

        if (usesJoining == this.usesJoining) {
            return;
        }
        this.usesJoining = usesJoining;

        // For 3524579 now cache joined mappings on the object builder.
        // This allows a user to set joining dynamically after the
        // descriptors have been initialized.  Generally this is not
        // supported, but since we were checking this flag in prepare after
        // initialization some degree of backward compatibility should be
        // provided.
        if (getDescriptor() != null) {
            getDescriptor().reInitializeJoinedAttributes();
        }

        // Still every query which is already prepared, like all selection
        // queries, will not pick up this change.
    
public booleanshouldUseJoining()
PUBLIC: Indicates whether the referenced object should always be joined on read queries. Joining will join the two classes tables to read all of the data in a single query. This should only be used if it is know that the related objects are always required with the source object, or indirection is not used.

        return usesJoining;
    
public booleanshouldVerifyDelete()
PUBLIC: Verify delete is used during delete and update outside of a unit of work only. It checks for the previous value of the target object through joining the source and target tables.

        return shouldVerifyDelete;
    
public voiduseJoining()
PUBLIC: Indicates whether the referenced object should always be joined on read queries. Joining will join the two classes tables to read all of the data in a single query. This should only be used if it is know that the related objects are always required with the source object, or indirection is not used.

        setUsesJoining(true);
    
public java.lang.ObjectvalueFromObject(java.lang.Object object, DatabaseField field, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Get a value from the object and set that in the respective field of the row.

        // First check if the value can be obtained from the value holder's row.
        AbstractRecord referenceRow = getIndirectionPolicy().extractReferenceRow(getAttributeValueFromObject(object));
        if (referenceRow != null) {
            Object value = referenceRow.get(field);

            // Must ensure the classification to get a cache hit.
            try {
                value = session.getDatasourcePlatform().convertObject(value, getFieldClassification(field));
            } catch (ConversionException e) {
                throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
            }
            return value;
        }

        Object referenceObject = getRealAttributeValueFromObject(object, session);
        if (referenceObject == null) {
            return null;
        }
        DatabaseField targetField = (DatabaseField)getSourceToTargetKeyFields().get(field);

        return getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(referenceObject, targetField, session);
    
protected java.lang.ObjectvalueFromRowInternal(oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractSession executionSession)
INTERNAL: Return the value of the field from the row or a value holder on the query to obtain the object. Check for batch + aggregation reading.

        // If any field in the foreign key is null then it means there are no referenced objects
        // Skip for partial objects as fk may not be present.
        int size = this.fields.size();
        for (int index = 0; index < size; index++) {
            DatabaseField field = (DatabaseField)this.fields.get(index);
            if (row.get(field) == null) {
                return this.indirectionPolicy.nullValueFromRow();
            }
        }

        // Call the default which executes the selection query,
        // or wraps the query with a value holder.
        return super.valueFromRowInternal(row, joinManager, executionSession);
    
protected java.lang.ObjectvalueFromRowInternalWithJoin(oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractSession executionSession)
INTERNAL: If the query used joining or partial attributes, build the target object directly.

        // PERF: Direct variable access.
        Object referenceObject;
        // CR #... the field for many objects may be in the row,
        // so build the subpartion of the row through the computed values in the query,
        // this also helps the field indexing match.
        AbstractRecord targetRow = trimRowForJoin(row, joinManager, executionSession);
        // PERF: Only check for null row if an outer-join was used.
        if (joinManager.isAttributeJoined(getDescriptor(), getAttributeName()) && joinManager.hasOuterJoinedAttributeQuery()) {
            Vector key = this.referenceDescriptor.getObjectBuilder().extractPrimaryKeyFromRow(targetRow, executionSession);
            if (key == null) {
                return this.indirectionPolicy.nullValueFromRow();
            }
        }
        // A nested query must be built to pass to the descriptor that looks like the real query execution would,
        // these should be cached on the query during prepare.
        ObjectLevelReadQuery nestedQuery = null;
        if (joinManager.getJoinedMappingQueries_() != null) {
            nestedQuery = (ObjectLevelReadQuery) joinManager.getJoinedMappingQueries_().get(this);
        } else {
            nestedQuery = prepareNestedJoins(joinManager, executionSession);
        }
        nestedQuery = (ObjectLevelReadQuery)nestedQuery.clone();
        nestedQuery.setTranslationRow(targetRow);
        nestedQuery.setSession(executionSession);            
        //CR #4365 - used to prevent infinite recursion on refresh object cascade all
        nestedQuery.setQueryId(joinManager.getBaseQuery().getQueryId());
        referenceObject = this.referenceDescriptor.getObjectBuilder().buildObject(nestedQuery, targetRow, nestedQuery.getJoinedAttributeManager());

        // For bug 3641713 buildObject doesn't wrap if called on a UnitOfWork for performance reasons,
        // must wrap here as this is the last time we can look at the query and tell whether to wrap or not.
        if (nestedQuery.shouldUseWrapperPolicy() && nestedQuery.getSession().isUnitOfWork()) {
            referenceObject = this.referenceDescriptor.getObjectBuilder().wrapObject(referenceObject, nestedQuery.getSession());
        }
        return this.indirectionPolicy.valueFromRow(referenceObject);
    
public voidwriteFromAttributeIntoRow(java.lang.Object attribute, oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: A subclass should implement this method if it wants different behaviour. Write the foreign key values from the attribute to the row.

          for (Enumeration fieldsEnum = getForeignKeyFields().elements(); fieldsEnum.hasMoreElements();) {
                  DatabaseField sourceKey = (DatabaseField) fieldsEnum.nextElement();
                  DatabaseField targetKey = (DatabaseField) getSourceToTargetKeyFields().get(sourceKey);
                  Object referenceValue = null;
                          // If privately owned part is null then method cannot be invoked.
                  if (attribute != null) {
                          referenceValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(attribute, targetKey, session);
                  }
                  row.add(sourceKey, referenceValue);
          }
    
public voidwriteFromObjectIntoRow(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Get a value from the object and set that in the respective field of the row.

        if (isReadOnly() || (!isForeignKeyRelationship())) {
            return;
        }

        AbstractRecord referenceRow = getIndirectionPolicy().extractReferenceRow(getAttributeValueFromObject(object));
        if (referenceRow == null) {
            // Extract from object.
            Object referenceObject = getRealAttributeValueFromObject(object, session);

            for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                     fieldsEnum.hasMoreElements();) {
                DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
                DatabaseField targetKey = (DatabaseField)getSourceToTargetKeyFields().get(sourceKey);

                Object referenceValue = null;

                // If privately owned part is null then method cannot be invoked.
                if (referenceObject != null) {
                    referenceValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(referenceObject, targetKey, session);
                }
                databaseRow.add(sourceKey, referenceValue);
            }
        } else {
            for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                     fieldsEnum.hasMoreElements();) {
                DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
                Object referenceValue = referenceRow.get(sourceKey);
                databaseRow.add(sourceKey, referenceValue);
            }
        }
    
public voidwriteFromObjectIntoRowForShallowDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This row is built for shallow update which happens in case of bidirectional deletes.

        writeFromObjectIntoRowForShallowOperation(object, databaseRow, session);
    
public voidwriteFromObjectIntoRowForShallowInsert(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This row is built for shallow insert which happens in case of bidirectional inserts.

        writeFromObjectIntoRowForShallowOperation(object, databaseRow, session);
    
public voidwriteFromObjectIntoRowForShallowInsertWithChangeRecord(ChangeRecord ChangeRecord, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This row is built for shallow insert which happens in case of bidirectional inserts. The foreign keys must be set to null to avoid constraints.

        if (isReadOnly() || (!isForeignKeyRelationship())) {
            return;
        }

        for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
            databaseRow.add(sourceKey, null);
        }
    
protected voidwriteFromObjectIntoRowForShallowOperation(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This row is built for shallow insert or delete which happens in case of bidirectional relationships. The foreign keys must be set to null to avoid foreign key constraint violations.

        if (isReadOnly() || (!isForeignKeyRelationship())) {
            return;
        }

        for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
            databaseRow.add(sourceKey, null);
        }
    
public voidwriteFromObjectIntoRowWithChangeRecord(ChangeRecord changeRecord, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Get a value from the object and set that in the respective field of the row. Validation preventing primary key updates is implemented here.

        if (isReadOnly() || (!isForeignKeyRelationship())) {
            return;
        }

        if (isPrimaryKeyMapping() && !changeRecord.getOwner().isNew()) {
           throw ValidationException.primaryKeyUpdateDisallowed(changeRecord.getOwner().getClassName(), changeRecord.getAttribute());
        }
        
        // the object must be used here as the foreign key may include more than just the
        // primary key of the referenced object and the changeSet may not have the rquired information
        Object object = ((ObjectChangeSet)changeRecord.getOwner()).getUnitOfWorkClone();
        AbstractRecord referenceRow = getIndirectionPolicy().extractReferenceRow(getAttributeValueFromObject(object));
        if (referenceRow == null) {
            // Extract from object.
            Object referenceObject = getRealAttributeValueFromObject(object, session);

            for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                     fieldsEnum.hasMoreElements();) {
                DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
                DatabaseField targetKey = (DatabaseField)getSourceToTargetKeyFields().get(sourceKey);

                Object referenceValue = null;

                // If privately owned part is null then method cannot be invoked.
                if (referenceObject != null) {
                    referenceValue = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(referenceObject, targetKey, session);
                }
                databaseRow.add(sourceKey, referenceValue);
            }
        } else {
            for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                     fieldsEnum.hasMoreElements();) {
                DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
                Object referenceValue = referenceRow.get(sourceKey);
                databaseRow.add(sourceKey, referenceValue);
            }
        }
    
public voidwriteInsertFieldsIntoRow(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Write fields needed for insert into the template for with null values.

        if (isReadOnly() || (!isForeignKeyRelationship())) {
            return;
        }

        for (Enumeration fieldsEnum = getForeignKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            DatabaseField sourceKey = (DatabaseField)fieldsEnum.nextElement();
            databaseRow.add(sourceKey, null);
        }