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

ObjectReferenceMapping

public abstract class ObjectReferenceMapping extends ForeignReferenceMapping

Purpose: Abstract class for 1:1, varibale 1:1 and reference mappings

Fields Summary
protected boolean
isForeignKeyRelationship
Keeps track if any of the fields are foreign keys.
protected Vector
foreignKeyFields
Keeps track of which fields are foreign keys on a per field basis (can have mixed foreign key relationships).
Constructors Summary
protected ObjectReferenceMapping()

        super();
    
Methods Summary
public java.lang.ObjectbuildBackupCloneForPartObject(java.lang.Object attributeValue, java.lang.Object clone, java.lang.Object backup, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
INTERNAL: Used during building the backup shallow copy to copy the vector without re-registering the target objects. For 1-1 or ref the reference is from the clone so it is already registered.

        return attributeValue;
    
public oracle.toplink.essentials.internal.sessions.ChangeRecordbuildChangeRecord(java.lang.Object clone, oracle.toplink.essentials.internal.sessions.ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Directly build a change record without comparison

        return internalBuildChangeRecord(getRealAttributeValueFromObject(clone, session), owner, session);
    
public java.lang.ObjectbuildCloneForPartObject(java.lang.Object attributeValue, java.lang.Object original, java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean isExisting)
INTERNAL: Require for cloning, the part must be cloned. Ignore the objects, use the attribute value.

        // Optimize registration to knowledge of existence.
        if (isExisting) {
            return unitOfWork.registerExistingObject(attributeValue);
        } else {
            // Not known wether existing or not.
            return unitOfWork.registerObject(attributeValue);
        }
    
public voidbuildCopy(java.lang.Object copy, java.lang.Object original, oracle.toplink.essentials.sessions.ObjectCopyingPolicy policy)
INTERNAL: Copy of the attribute of the object. This is NOT used for unit of work but for templatizing an object.

        Object attributeValue = getRealAttributeValueFromObject(original, policy.getSession());
        if ((attributeValue != null) && (policy.shouldCascadeAllParts() || (policy.shouldCascadePrivateParts() && isPrivateOwned()))) {
            attributeValue = policy.getSession().copyObject(attributeValue, policy);
        } else if (attributeValue != null) {
            // Check for copy of part, i.e. back reference.
            Object copyValue = policy.getCopies().get(attributeValue);
            if (copyValue != null) {
                attributeValue = copyValue;
            }
        }
        setRealAttributeValueInObject(copy, attributeValue);
    
protected booleancacheKeysAreEqual(oracle.toplink.essentials.internal.identitymaps.CacheKey cacheKey1, oracle.toplink.essentials.internal.identitymaps.CacheKey cacheKey2)
INTERNAL:

        return cacheKey1.equals(cacheKey2);
    
public voidcascadePerformRemoveIfRequired(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, oracle.toplink.essentials.internal.helper.IdentityHashtable visitedObjects)
INTERNAL: Cascade registerNew for Create through mappings that require the cascade

        Object attributeValue = getAttributeValueFromObject(object);
        if (attributeValue != null && this.isCascadeRemove() ){
            Object reference = getIndirectionPolicy().getRealAttributeValueFromObject(object, attributeValue);
            if (reference != null && (! visitedObjects.contains(reference)) ){
                visitedObjects.put(reference, reference);
                uow.performRemove(reference, visitedObjects);
            }
        }
    
public voidcascadeRegisterNewIfRequired(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, oracle.toplink.essentials.internal.helper.IdentityHashtable visitedObjects)
INTERNAL: Cascade registerNew for Create through mappings that require the cascade

        Object attributeValue = getAttributeValueFromObject(object);
        if (attributeValue != null && this.isCascadePersist() && getIndirectionPolicy().objectIsInstantiated(attributeValue)){
            Object reference = getIndirectionPolicy().getRealAttributeValueFromObject(object, attributeValue);
            if (reference != null && (! visitedObjects.contains(reference)) ){
                visitedObjects.put(reference, reference);
                uow.registerNewObjectForPersist(reference, visitedObjects);
            }
        }
    
protected java.util.VectorcollectFields()
INTERNAL: Return all the fields populated by this mapping, these are foreign keys only.

        return getForeignKeyFields();
    
public oracle.toplink.essentials.internal.sessions.ChangeRecordcompareForChange(java.lang.Object clone, java.lang.Object backUp, oracle.toplink.essentials.internal.sessions.ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This method was created in VisualAge.

return
prototype.changeset.ChangeRecord

        Object cloneAttribute = null;
        Object backUpAttribute = null;

        cloneAttribute = getAttributeValueFromObject(clone);

        if (!owner.isNew()) {
            backUpAttribute = getAttributeValueFromObject(backUp);
            if ((backUpAttribute == null) && (cloneAttribute == null)) {
                return null;
            }
        }

        if ((cloneAttribute != null) && (!getIndirectionPolicy().objectIsInstantiated(cloneAttribute))) {
            //the clone's valueholder was never triggered so there will be no change
            return null;
        }
        Object cloneAttributeValue = null;
        Object backUpAttributeValue = null;

        if (cloneAttribute != null) {
            cloneAttributeValue = getRealAttributeValueFromObject(clone, session);
        }
        if (backUpAttribute != null) {
            backUpAttributeValue = getRealAttributeValueFromObject(backUp, session);
        }

        if ((cloneAttributeValue == backUpAttributeValue) && (!owner.isNew())) {// if it is new record the value
            return null;
        }

        ObjectReferenceChangeRecord record = internalBuildChangeRecord(cloneAttributeValue, owner, session);
        if (!owner.isNew()) {
            record.setOldValue(backUpAttributeValue);
        }
        return record;
    
protected booleancompareObjectsWithPrivateOwned(java.lang.Object firstObject, java.lang.Object secondObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Compare the references of the two objects are the same, and the objects themselves are the same. Used for private relationships. This is used for testing and validation purposes.

        Object firstPrivateObject = getRealAttributeValueFromObject(firstObject, session);
        Object secondPrivateObject = getRealAttributeValueFromObject(secondObject, session);

        return session.compareObjects(firstPrivateObject, secondPrivateObject);
    
protected booleancompareObjectsWithoutPrivateOwned(java.lang.Object firstObject, java.lang.Object secondObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Compare the references of the two objects are the same, not the objects themselves. Used for independent relationships. This is used for testing and validation purposes.

        Object firstReferencedObject = getRealAttributeValueFromObject(firstObject, session);
        Object secondReferencedObject = getRealAttributeValueFromObject(secondObject, session);

        if ((firstReferencedObject == null) && (secondReferencedObject == null)) {
            return true;
        }

        if ((firstReferencedObject == null) || (secondReferencedObject == null)) {
            return false;
        }

        Vector firstKey = getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(firstReferencedObject, session);
        Vector secondKey = getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(secondReferencedObject, session);

        for (int index = 0; index < firstKey.size(); index++) {
            Object firstValue = firstKey.elementAt(index);
            Object secondValue = secondKey.elementAt(index);

            if (!((firstValue == null) && (secondValue == null))) {
                if ((firstValue == null) || (secondValue == null)) {
                    return false;
                }
                if (!firstValue.equals(secondValue)) {
                    return false;
                }
            }
        }

        return true;
    
public oracle.toplink.essentials.internal.indirection.UnitOfWorkValueHoldercreateUnitOfWorkValueHolder(oracle.toplink.essentials.indirection.ValueHolderInterface attributeValue, java.lang.Object original, java.lang.Object clone, oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRow)
INTERNAL: Builder the unit of work value holder.

param
buildDirectlyFromRow indicates that we are building the clone directly from a row as opposed to building the original from the row, putting it in the shared cache, and then cloning the original.

        UnitOfWorkQueryValueHolder valueHolder = null;
        if ((row == null) && (getDescriptor().getObjectBuilder().isPrimaryKeyMapping(this))) {
            // The row must be built if a primary key mapping for remote case.
            AbstractRecord rowFromTargetObject = extractPrimaryKeyRowForSourceObject(original, unitOfWork);
            valueHolder = new UnitOfWorkQueryValueHolder(attributeValue, clone, this, rowFromTargetObject, unitOfWork);
        } else {
            valueHolder = new UnitOfWorkQueryValueHolder(attributeValue, clone, this, row, unitOfWork);
        }

        // In case of joined attributes it so happens that the attributeValue 
        // contains a registered clone, as valueFromRow was called with a
        // UnitOfWork.  So switch the values.
        // Note that this UOW valueholder starts off as instantiated but that
        // is fine, for the reality is that it is.
        if (buildDirectlyFromRow && attributeValue.isInstantiated()) {
            Object cloneAttributeValue = attributeValue.getValue();
            valueHolder.privilegedSetValue(cloneAttributeValue);
            valueHolder.setInstantiated();

            // PERF: Do not modify the original value-holder, it is never used.
        }
        return valueHolder;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordextractPrimaryKeyRowForSourceObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the reference pk for rvh usage in remote model.

        AbstractRecord databaseRow = getDescriptor().getObjectBuilder().createRecord();
        writeFromObjectIntoRow(domainObject, databaseRow, session);
        return databaseRow;
    
public java.util.VectorextractPrimaryKeysForReferenceObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the reference pk for rvh usage in remote model.

        return getIndirectionPolicy().extractPrimaryKeyForReferenceObject(getAttributeValueFromObject(domainObject), session);
    
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.

        return new Vector(1);
    
public java.util.VectorextractPrimaryKeysFromRealReferenceObject(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the reference pk for rvh usage in remote model.

        if (object == null) {
            return new Vector(1);
        } else {
            Object implementation = getReferenceDescriptor().getObjectBuilder().unwrapObject(object, session);
            return getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(implementation, session);
        }
    
public oracle.toplink.essentials.descriptors.ClassDescriptorgetDescriptorForTarget(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return a descriptor for the target of this mapping

see
oracle.toplink.essentials.mappings.VariableOneToOneMapping Bug 2612571

        return session.getDescriptor(object);
    
public java.util.VectorgetForeignKeyFields()
INTERNAL: Returns the foreign key names associated with the mapping. These are the fields that will be populated by the 1-1 mapping when writting.

        return foreignKeyFields;
    
protected java.util.VectorgetPrimaryKeyForObject(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL:

        return getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(object, session);
    
public java.lang.ObjectgetRealAttributeValueFromObject(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Object reference must unwrap the reference object if required.

        Object value = super.getRealAttributeValueFromObject(object, session);
        value = getReferenceDescriptor().getObjectBuilder().unwrapObject(value, session);

        return value;
    
public booleanhasConstraintDependency()
INTERNAL: The returns if the mapping has any constraint dependencies, such as foreign keys and join tables.

        return isForeignKeyRelationship();
    
protected voidinsert(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Insert the referenced objects.

        // Insertion takes place according the the cascading policy
        if (!shouldObjectModifyCascadeToParts(query)) {
            return;
        }

        // Get the privately owned parts
        Object object = getRealAttributeValueFromObject(query.getObject(), query.getSession());

        if (object == null) {
            return;
        }
        ObjectChangeSet changeSet = query.getObjectChangeSet();
        if (changeSet != null) {
            ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)query.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
            if (changeRecord != null) {
                changeSet = (ObjectChangeSet)changeRecord.getNewValue();
            } else {
                // no changeRecord no reference.
                return;
            }
        } else {
            UnitOfWorkChangeSet uowChangeSet = null;

            // get changeSet for referenced object.  Could get it from the changeRecord but that would as much work
            if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
                uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
                changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(object);
            }
        }

        WriteObjectQuery writeQuery = null;
        if (isPrivateOwned()) {
            // no identity check needed for private owned
            writeQuery = new InsertObjectQuery();
        } else {
            writeQuery = new WriteObjectQuery();
        }
        writeQuery.setObject(object);
        writeQuery.setObjectChangeSet(changeSet);
        writeQuery.setCascadePolicy(query.getCascadePolicy());
        query.getSession().executeQuery(writeQuery);
    
public oracle.toplink.essentials.internal.sessions.ObjectReferenceChangeRecordinternalBuildChangeRecord(java.lang.Object newValue, oracle.toplink.essentials.internal.sessions.ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Directly build a change record based on the newValue without comparison

        ObjectReferenceChangeRecord changeRecord = new ObjectReferenceChangeRecord(owner);
        changeRecord.setAttribute(getAttributeName());
        changeRecord.setMapping(this);
        setNewValueInChangeRecord(newValue, changeRecord, owner, session);
        return changeRecord;
    
public booleanisChangeTrackingSupported()
INTERNAL: Return if this mapping supports change tracking.

        return true;
    
public booleanisForeignKeyRelationship()
INTERNAL: Return if the 1-1 mapping has a foreign key dependency to its target. This is true if any of the foreign key fields are true foreign keys, i.e. populated on write from the targets primary key.

        return isForeignKeyRelationship;
    
public booleanisObjectReferenceMapping()
INTERNAL: Related mapping should implement this method to return true.

        return true;
    
public voiditerateOnRealAttributeValue(oracle.toplink.essentials.internal.descriptors.DescriptorIterator iterator, java.lang.Object realAttributeValue)
INTERNAL: Iterate on the attribute value. The value holder has already been processed.

        // This may be wrapped as the caller in iterate on foreign reference does not unwrap as the type is generic.
        Object unwrappedAttributeValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(realAttributeValue, iterator.getSession());
        iterator.iterateReferenceObjectForMapping(unwrappedAttributeValue, this);
    
public voidmergeChangesIntoObject(java.lang.Object target, oracle.toplink.essentials.internal.sessions.ChangeRecord changeRecord, java.lang.Object source, oracle.toplink.essentials.internal.sessions.MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object. Which is the original from the parent UnitOfWork

        Object targetValueOfSource = null;

        // The target object must be completely merged before setting it otherwise
        // another thread can pick up the partial object.
        if (shouldMergeCascadeParts(mergeManager)) {
            ObjectChangeSet set = (ObjectChangeSet)((ObjectReferenceChangeRecord)changeRecord).getNewValue();
            if (set != null) {
                if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
                    //Let's try and find it first.  We may have merged it allready. In which case merge
                    //changes will  stop the recursion
                    targetValueOfSource = set.getTargetVersionOfSourceObject(mergeManager.getSession(), false);
                    if ((targetValueOfSource == null) && (set.isNew() || set.isAggregate()) && set.containsChangesFromSynchronization()) {
                        if (!mergeManager.getObjectsAlreadyMerged().containsKey(set)) {
                            // if we haven't merged this object allready then build a new object
                            // otherwise leave it as null which will stop the recursion
                            // CR 2855
                            // CR 3424 Need to build the right instance based on class type instead of refernceDescriptor
                            Class objectClass = set.getClassType(mergeManager.getSession());
                            targetValueOfSource = mergeManager.getSession().getDescriptor(objectClass).getObjectBuilder().buildNewInstance();
                            //Store the changeset to prevent us from creating this new object again
                            mergeManager.getObjectsAlreadyMerged().put(set, targetValueOfSource);
                        } else {
                            //CR 4012
                            //we have all ready created the object, must be in a cyclic
                            //merge on a new object so get it out of the allreadymerged collection
                            targetValueOfSource = mergeManager.getObjectsAlreadyMerged().get(set);
                        }
                    } else {
                        // If We have not found it anywhere else load it from the database
                        targetValueOfSource = set.getTargetVersionOfSourceObject(mergeManager.getSession(), true);
                    }
                    if (set.containsChangesFromSynchronization()) {
                        mergeManager.mergeChanges(targetValueOfSource, set);
                    }
                    //bug:3604593 - ensure reference not changed source is invalidated if target object not found
                    if (targetValueOfSource ==null)
                    {
                      mergeManager.getSession().getIdentityMapAccessorInstance().invalidateObject(target);
                      return;
                    }
                } else {
                    mergeManager.mergeChanges(set.getUnitOfWorkClone(), set);
                }
            }
        }
        if ((targetValueOfSource == null) && (((ObjectReferenceChangeRecord)changeRecord).getNewValue() != null)) {
            targetValueOfSource = ((ObjectChangeSet)((ObjectReferenceChangeRecord)changeRecord).getNewValue()).getTargetVersionOfSourceObject(mergeManager.getSession());
        }

        // Register new object in nested units of work must not be registered into the parent,
        // so this records them in the merge to parent case.
        if (isPrivateOwned() && (source != null)) {
            mergeManager.registerRemovedNewObjectIfRequired(getRealAttributeValueFromObject(source, mergeManager.getSession()));
        }

        targetValueOfSource = getReferenceDescriptor().getObjectBuilder().wrapObject(targetValueOfSource, mergeManager.getSession());
        setRealAttributeValueInObject(target, targetValueOfSource);
    
public voidmergeIntoObject(java.lang.Object target, boolean isTargetUnInitialized, java.lang.Object source, oracle.toplink.essentials.internal.sessions.MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object.

        if (isTargetUnInitialized) {
            // This will happen if the target object was removed from the cache before the commit was attempted
            if (mergeManager.shouldMergeWorkingCopyIntoOriginal() && (!isAttributeValueInstantiated(source))) {
                setAttributeValueInObject(target, getIndirectionPolicy().getOriginalIndirectionObject(getAttributeValueFromObject(source), mergeManager.getSession()));
                return;
            }
        }
        if (!shouldMergeCascadeReference(mergeManager)) {
            // This is only going to happen on mergeClone, and we should not attempt to merge the reference
            return;
        }
        if (mergeManager.shouldMergeOriginalIntoWorkingCopy()) {
            if (!isAttributeValueInstantiated(target)) {
                // This will occur when the clone's value has not been instantiated yet and we do not need
                // the refresh that attribute
                return;
            }
        } else if (!isAttributeValueInstantiated(source)) {
            // I am merging from a clone into an original.  No need to do merge if the attribute was never
            // modified
            return;
        }

        Object valueOfSource = getRealAttributeValueFromObject(source, mergeManager.getSession());

        Object targetValueOfSource = null;

        // The target object must be completely merged before setting it otherwise
        // another thread can pick up the partial object.
        if (shouldMergeCascadeParts(mergeManager) && (valueOfSource != null)) {
            if ((mergeManager.getSession().isUnitOfWork()) && (((UnitOfWorkImpl)mergeManager.getSession()).getUnitOfWorkChangeSet() != null)) {
                // If it is a unit of work, we have to check if I have a change Set fot this object
                mergeManager.mergeChanges(mergeManager.getObjectToMerge(valueOfSource), (ObjectChangeSet)((UnitOfWorkChangeSet)((UnitOfWorkImpl)mergeManager.getSession()).getUnitOfWorkChangeSet()).getObjectChangeSetForClone(valueOfSource));
            } else {
                mergeManager.mergeChanges(mergeManager.getObjectToMerge(valueOfSource), null);
            }
        }

        if (valueOfSource != null) {
            // Need to do this after merge so that an object exists in the database
            targetValueOfSource = mergeManager.getTargetVersionOfSourceObject(valueOfSource);
        }

        if (this.getDescriptor().getObjectChangePolicy().isObjectChangeTrackingPolicy()) {
            // Object level or attribute level so lets see if we need to raise the event?
            Object valueOfTarget = getRealAttributeValueFromObject(target, mergeManager.getSession());
            if ( valueOfTarget != targetValueOfSource ) { //equality comparison cause both are uow clones
                this.getDescriptor().getObjectChangePolicy().raiseInternalPropertyChangeEvent(target, getAttributeName(), valueOfTarget, targetValueOfSource);
            }
        }
 
        targetValueOfSource = getReferenceDescriptor().getObjectBuilder().wrapObject(targetValueOfSource, mergeManager.getSession());
        setRealAttributeValueInObject(target, targetValueOfSource);
    
public voidpostDelete(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Delete the referenced objects.

        // Deletion takes place according the the cascading policy
        if (!shouldObjectModifyCascadeToParts(query)) {
            return;
        }

        // There are no dependencies after this object has been deleted successfully!
        if (query.shouldCascadeOnlyDependentParts() && !isPrivateOwned()) {
            return;
        }

        Object object = query.getProperty(this);

        // The object is stored in the query by preDeleteForObjectUsing(...).
        if (isForeignKeyRelationship()) {
            if (object != null) {
                query.removeProperty(this);

                //if the query is being passed from an aggregate collection descriptor then 
                // The delete will have been cascaded at update time.  This will cause sub objects
                // to be ignored, and real only classes to throw exceptions.
                // If it is an aggregate Collection then delay deletes until they should be deleted
                //CR 2811	
                if (query.isCascadeOfAggregateDelete()) {
                    query.getSession().getCommitManager().addObjectToDelete(object);
                } else {
                    DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
                    deleteQuery.setObject(object);
                    deleteQuery.setCascadePolicy(query.getCascadePolicy());
                    query.getSession().executeQuery(deleteQuery);
                }
            }
        }
    
public voidpostInsert(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Insert privately owned parts

        if (!isForeignKeyRelationship()) {
            insert(query);
        }
    
public voidpostUpdate(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Update privately owned parts

        if (!isAttributeValueInstantiated(query.getObject())) {
            return;
        }

        if (!isForeignKeyRelationship()) {
            update(query);
        }

        // If a private owned reference was changed the old value will be set on the query as a property.
        Object objectInDatabase = query.getProperty(this);
        if (objectInDatabase != null) {
            query.removeProperty(this);
        } else {
            return;
        }

        // If there is no change (old commit), it must be determined if the value changed.
        if (query.getObjectChangeSet() == null) {
            Object objectInMemory = getRealAttributeValueFromObject(query.getObject(), query.getSession());
    
            // delete the object in the database if it is no more a referenced object.						
            if (objectInDatabase != objectInMemory) {
                CacheKey cacheKeyForObjectInDatabase = null;
                CacheKey cacheKeyForObjectInMemory = new CacheKey(new Vector());
    
                cacheKeyForObjectInDatabase = new CacheKey(getPrimaryKeyForObject(objectInDatabase, query.getSession()));
    
                if (objectInMemory != null) {
                    cacheKeyForObjectInMemory = new CacheKey(getPrimaryKeyForObject(objectInMemory, query.getSession()));
                }
    
                if (cacheKeysAreEqual(cacheKeyForObjectInDatabase, cacheKeyForObjectInMemory)) {
                    return;
                }
            } else {
                return;
            }
        }            
            
        if (query.shouldCascadeOnlyDependentParts()) {
            query.getSession().getCommitManager().addObjectToDelete(objectInDatabase);
        } else {
            query.getSession().deleteObject(objectInDatabase);
        }
    
public voidpreDelete(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Delete the referenced objects.

        // Deletion takes place according the the cascading policy
        if (!shouldObjectModifyCascadeToPartsForPreDelete(query)) {
            return;
        }

        // Get the referenced objects.
        Object objectInMemory = getRealAttributeValueFromObject(query.getObject(), query.getSession());
        Object objectFromDatabase = null;

        // Because the value in memory may have been changed we check the previous value or database value.
        objectFromDatabase = readPrivateOwnedForObject(query);

        // If the value was changed, both values must be deleted (uow will have inserted the new one).
        if ((objectFromDatabase != null) && (objectFromDatabase != objectInMemory)) {
            // Also check pk as may not be maintaining identity.			
            CacheKey cacheKeyForObjectInDatabase = null;
            CacheKey cacheKeyForObjectInMemory = new CacheKey(new Vector());

            cacheKeyForObjectInDatabase = new CacheKey(getPrimaryKeyForObject(objectFromDatabase, query.getSession()));

            if (objectInMemory != null) {
                cacheKeyForObjectInMemory = new CacheKey(getPrimaryKeyForObject(objectInMemory, query.getSession()));
            }
            if (!cacheKeysAreEqual(cacheKeyForObjectInMemory, cacheKeyForObjectInDatabase)) {
                if (objectFromDatabase != null) {
                    // Make sure only objects sheduled for deletion are deleted
                    if (shouldObjectDeleteCascadeToPart(query, objectFromDatabase)) {
                        DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
                        deleteQuery.setObject(objectFromDatabase);
                        deleteQuery.setCascadePolicy(query.getCascadePolicy());
                        query.getSession().executeQuery(deleteQuery);
                    }
                }
            }
        }

        if (!isForeignKeyRelationship()) {
            if (objectInMemory != null) {
                // Make sure only objects sheduled for deletion are deleted
                if (shouldObjectDeleteCascadeToPart(query, objectInMemory)) {
                    DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
                    deleteQuery.setObject(objectInMemory);
                    deleteQuery.setCascadePolicy(query.getCascadePolicy());
                    query.getSession().executeQuery(deleteQuery);
                }
            }
        } else {
            // The actual deletion of part takes place in postDelete(...).
            if (objectInMemory != null) {
                query.setProperty(this, objectInMemory);
            }
        }
    
public voidpreInsert(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Insert privately owned parts

        if (isForeignKeyRelationship()) {
            insert(query);
        }
    
public voidpreUpdate(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Update privately owned parts

        if (!isAttributeValueInstantiated(query.getObject())) {
            return;
        }

        if (isPrivateOwned()) {
            Object objectInDatabase = readPrivateOwnedForObject(query);
            if (objectInDatabase != null) {
                query.setProperty(this, objectInDatabase);
            }
        }

        if (!isForeignKeyRelationship()) {
            return;
        }

        update(query);
    
protected java.lang.ObjectreadPrivateOwnedForObject(oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery modifyQuery)
INTERNAL: Reads the private owned object.

        if (modifyQuery.getSession().isUnitOfWork()) {
            if (modifyQuery.getObjectChangeSet() != null) {
                ObjectReferenceChangeRecord record = (ObjectReferenceChangeRecord) modifyQuery.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
                if (record != null) {
                    return record.getOldValue();
                } 
            } else { // Old commit.
                return getRealAttributeValueFromObject(modifyQuery.getBackupClone(), modifyQuery.getSession());
            }
        }
        
        return null;
    
protected voidsetForeignKeyFields(java.util.Vector foreignKeyFields)
INTERNAL: Set the foreign key fields associated with the mapping. These are the fields that will be populated by the 1-1 mapping when writting.

        this.foreignKeyFields = foreignKeyFields;
        if (!foreignKeyFields.isEmpty()) {
            setIsForeignKeyRelationship(true);
        }
    
public voidsetIsForeignKeyRelationship(boolean isForeignKeyRelationship)
INTERNAL: Set if the 1-1 mapping has a foreign key dependency to its target. This is true if any of the foreign key fields are true foreign keys, i.e. populated on write from the targets primary key.

        this.isForeignKeyRelationship = isForeignKeyRelationship;
    
public voidsetNewValueInChangeRecord(java.lang.Object newValue, oracle.toplink.essentials.internal.sessions.ObjectReferenceChangeRecord changeRecord, oracle.toplink.essentials.internal.sessions.ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Set the newValue in the change record

        if (newValue != null) {
            // Bug 2612571 - added more flexible manner of getting descriptor
            ObjectChangeSet newSet = getDescriptorForTarget(newValue, session).getObjectBuilder().createObjectChangeSet(newValue, (UnitOfWorkChangeSet)owner.getUOWChangeSet(), session);
            changeRecord.setNewValue(newSet);
        } else {
            changeRecord.setNewValue(null);
        }
    
protected voidupdate(oracle.toplink.essentials.queryframework.WriteObjectQuery query)
INTERNAL: Update the private owned part.

        if (!shouldObjectModifyCascadeToParts(query)) {
            return;
        }

        // If objects are not instantiated that means they are not changed.
        if (!isAttributeValueInstantiated(query.getObject())) {
            return;
        }

        // Get the privately owned parts in the memory
        Object object = getRealAttributeValueFromObject(query.getObject(), query.getSession());
        if (object != null) {
            ObjectChangeSet changeSet = query.getObjectChangeSet();
            if (changeSet != null) {
                ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)query.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
                if (changeRecord != null) {
                    changeSet = (ObjectChangeSet)changeRecord.getNewValue();
                } else {
                    // no changeRecord no change to reference.
                    return;
                }
            } else {
                UnitOfWorkChangeSet uowChangeSet = null;

                // get changeSet for referenced object.  Could get it from the changeRecord but that would as much work
                if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
                    uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
                    changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(object);
                }
            }
            WriteObjectQuery writeQuery = new WriteObjectQuery();
            writeQuery.setObject(object);
            writeQuery.setObjectChangeSet(changeSet);
            writeQuery.setCascadePolicy(query.getCascadePolicy());
            query.getSession().executeQuery(writeQuery);
        }
    
public voidupdateChangeRecord(java.lang.Object clone, java.lang.Object newValue, java.lang.Object oldValue, oracle.toplink.essentials.internal.sessions.ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Either create a new change record or update the change record with the new value. This is used by attribute change tracking.

        // Must ensure values are unwrapped.
        Object unwrappedNewValue = newValue;
        Object unwrappedOldValue = oldValue;
        if (newValue != null) {
            unwrappedNewValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(newValue, uow);
        }
        if (oldValue != null) {
            unwrappedOldValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(oldValue, uow);
        }
        ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null) {
            changeRecord = internalBuildChangeRecord(unwrappedNewValue, objectChangeSet, uow);
            changeRecord.setOldValue(unwrappedOldValue);
            objectChangeSet.addChange(changeRecord);
            
        } else {
            setNewValueInChangeRecord(unwrappedNewValue, changeRecord, objectChangeSet, uow);
        }
    
public booleanverifyDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: To verify if the specified object is deleted or not.

        if (isPrivateOwned()) {
            Object attributeValue = getRealAttributeValueFromObject(object, session);

            if (attributeValue != null) {
                return session.verifyDelete(attributeValue);
            }
        }

        return true;
    
public voidwriteFromObjectIntoRowForUpdate(oracle.toplink.essentials.queryframework.WriteObjectQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow)
INTERNAL: Get a value from the object and set that in the respective field of the row. But before that check if the reference object is instantiated or not.

        Object object = query.getObject();
        AbstractSession session = query.getSession();

        if (!isAttributeValueInstantiated(object)) {
            return;
        }

        if (session.isUnitOfWork()) {
            if (compareObjectsWithoutPrivateOwned(query.getBackupClone(), object, session)) {
                return;
            }
        }

        writeFromObjectIntoRow(object, databaseRow, session);
    
public voidwriteFromObjectIntoRowForWhereClause(oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow)
INTERNAL: Get a value from the object and set that in the respective field of the row.

        if (isReadOnly()) {
            return;
        }

        if (query.isDeleteObjectQuery()) {
            writeFromObjectIntoRow(query.getObject(), databaseRow, query.getSession());
        } else {
            // If the original was never instantiated the backup clone has a ValueHolder of null 
            // so for this case we must extract from the original object.
            if (isAttributeValueInstantiated(query.getObject())) {
                writeFromObjectIntoRow(query.getBackupClone(), databaseRow, query.getSession());
            } else {
                writeFromObjectIntoRow(query.getObject(), databaseRow, query.getSession());
            }
        }