}
else if (myLC != null)
{
boolean loadedOldValue = false;
Object oldValue = currentValue;
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(field);
ClassLoaderResolver clr = myOM.getClassLoaderResolver();
int relationType = fmd.getRelationType(clr);
if (!loadedFields[field] && currentValue == null)
{
// Updating value of a field that isnt currently loaded
if (myOM.getOMFContext().getPersistenceConfiguration().getBooleanProperty("org.jpox.manageRelationships") &&
(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 && fmd.isDependent() && newValue == null)
{
// 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
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));
}
}
writeField(field, newValue);
postWriteField(wasDirty);
}
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);
writeField(field, newValue);
postWriteField(wasDirty);
}
if (!equal &&
myOM.getOMFContext().getPersistenceConfiguration().getBooleanProperty("org.jpox.manageRelationships"))
{
// Managed Relations : register updated bidir fields for later processing
if (relationType == Relation.ONE_TO_ONE_BI ||
relationType == Relation.MANY_TO_ONE_BI ||
relationType == Relation.ONE_TO_MANY_BI ||
relationType == Relation.MANY_TO_MANY_BI)
{
// Managed Relationships - add the field to be managed so we can analyse its value at flush
if (relationManager == null)
{
relationManager = new RelationshipManager(this);
}
relationManager.relationChange(field, oldValue, newValue);
}
}
if (fmd.isDependent() && oldValue != null && newValue == null && oldValue instanceof PersistenceCapable)
{
// PC field being nulled, so delete previous PC value
// TODO Avoid this flush since it will screw up optimistic txn handling
flush(); // Make sure that any null reference is set first (to avoid any FK constraint failures)
JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("026026",
oldValue, fmd.getFullFieldName()));
myOM.deleteObjectInternal(oldValue);
}
}
else
{