loadUnloadedFieldsInFetchPlanAndVersion();
}
boolean loadedOldValue = false;
Object oldValue = currentValue;
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(field);
ClassLoaderResolver clr = myOM.getClassLoaderResolver();
int relationType = fmd.getRelationType(clr);
// Remove this object from L2 cache since now dirty to avoid potential problems
myOM.removeObjectFromLevel2Cache(myID);
if (!loadedFields[field] && currentValue == null)
{
// Updating value of a field that isnt currently loaded
if (myOM.getManageRelations() &&
(relationType == Relation.ONE_TO_ONE_BI || relationType == Relation.MANY_TO_ONE_BI))
{
// Managed relation field, so load old value
loadField(field);
loadedOldValue = true;
oldValue = provideField(field);
}
if (relationType != Relation.NONE && newValue == null &&
(fmd.isDependent() || fmd.isCascadeRemoveOrphans()))
{
// Field being nulled and is dependent so load the existing value so it can be deleted
loadField(field);
loadedOldValue = true;
oldValue = provideField(field);
}
// TODO When field has relation consider loading it always for managed relations
}
// Check equality of old and new values
boolean equal = false;
if (oldValue == null && newValue == null)
{
equal = true;
}
else if (oldValue != null && newValue != null)
{
if (oldValue instanceof PersistenceCapable)
{
// PC object field so compare object equality
// See JDO2 [5.4] "The JDO implementation must not use the application's hashCode and equals methods
// from the persistence-capable classes except as needed to implement the Collections Framework"
if (oldValue == newValue)
{
equal = true;
}
}
else
{
// Non-PC object field so compare using equals()
if (oldValue.equals(newValue))
{
equal = true;
}
}
}
// Update the field
boolean needsSCOUpdating = false;
if (!loadedFields[field] || !equal || fmd.hasArray())
{
// Either field isn't loaded, or has changed, or is an array.
// We include arrays here since we have no way of knowing if the array element has changed
// except if the user sets the array field. See JDO2 [6.3] that the application should
// replace the value with its current value.
boolean wasDirty = preWriteField(field);
if (oldValue instanceof SCO)
{
if (oldValue instanceof SCOContainer)
{
// Make sure container values are loaded
((SCOContainer)oldValue).load();
}
((SCO) oldValue).unsetOwner();
}
if (newValue instanceof SCO)
{
SCO sco = (SCO) newValue;
Object owner = sco.getOwner();
if (owner != null)
{
throw new JDOUserException(LOCALISER.msg("026007", sco.getFieldName(), owner));
}
}
replaceField(pc, field, newValue, true);
postWriteField(wasDirty);
if (cmd.getSCOMutableMemberFlags()[field] && !(newValue instanceof SCO))
{
// Need to wrap this field change
needsSCOUpdating = true;
}
}
else if (loadedOldValue)
{
// We've updated the value with the old value (when retrieving it above), so put the new value back again
boolean wasDirty = preWriteField(field);
replaceField(pc, field, newValue, true);
postWriteField(wasDirty);
}
if (!equal && Relation.isBidirectional(relationType)&& myOM.getManageRelations())
{
// Managed Relationships - add the field to be managed so we can analyse its value at flush
myOM.getRelationshipManager(this).relationChange(field, oldValue, newValue);
}
if (needsSCOUpdating)
{
// Wrap with SCO so we can detect future updates
newValue = wrapSCOField(field, newValue, false, true, true);
}
if (oldValue != null && newValue == null && oldValue instanceof PersistenceCapable)
{
if (fmd.isDependent() || fmd.isCascadeRemoveOrphans())
{
if (myOM.getApiAdapter().isPersistent(oldValue))
{
// PC field being nulled, so delete previous PC value
NucleusLogger.PERSISTENCE.debug(LOCALISER.msg("026026", oldValue, fmd.getFullFieldName()));
myOM.deleteObjectInternal(oldValue);
}
}
}
}