public void storeObjectField(int fieldNumber, Object value)
{
// Note : when doing updates always do replaceField first and makeDirty after since the replaceField
// can cause flush() to be called meaning that an update with null would be made before the new value
// makes it into the field
ApiAdapter api = smAttached.getObjectManager().getApiAdapter();
if (value == null)
{
Object oldValue = null;
AbstractClassMetaData cmd = smAttached.getClassMetaData();
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
if (fmd.isDependent())
{
try
{
// Get any old value of this field so we can do cascade-delete if being nulled
smAttached.loadFieldFromDatastore(fieldNumber);
}
catch (Exception e)
{
// Error loading the field so didnt exist before attaching anyway
}
oldValue = smAttached.provideField(fieldNumber);
}
if (dirtyFields[fieldNumber] || !persistent)
{
smAttached.replaceField(fieldNumber, null, true);
smAttached.makeDirty(fieldNumber);
}
if (fmd.isDependent() && !fmd.isEmbedded() &&
oldValue != null && value == null && api.isPersistable(oldValue))
{
// Check for a field storing a PC where it is being nulled and the other object is dependent
smAttached.flush(); // Flush the nulling of the field
JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("026026", oldValue, fmd.getFullFieldName()));
smAttached.getObjectManager().deleteObjectInternal(oldValue);
}
}
else if (secondClassMutableFields[fieldNumber])
{
AbstractMemberMetaData fmd =
smAttached.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
if (fmd.isSerialized())
{
// SCO Field is serialised so just update the column with this new value - dont do comparisons yet
smAttached.replaceField(fieldNumber, value, true);
smAttached.makeDirty(fieldNumber);
}
else
{
// Make sure that the value is a SCO wrapper
Object oldValue = smAttached.provideField(fieldNumber);
SCO sco;
if (oldValue == null || (oldValue != null && !(oldValue instanceof SCO)))
{
// The field wasn't initialised at creation, so create an empty SCO wrapper and copy the new values in
if (JPOXLogger.JDO.isDebugEnabled())
{
JPOXLogger.JDO.debug(LOCALISER.msg("026029", StringUtils.toJVMIDString(smAttached.getObject()),
smAttached.getInternalObjectId(), fmd.getName()));
}
sco = SCOUtils.newSCOInstance(smAttached, fmd, fmd.getType(), null, null, false, false, false);
if (sco instanceof SCOContainer)
{
// Load any containers to avoid update issues
((SCOContainer)sco).load();
}
smAttached.replaceField(fieldNumber, sco, true);
}
else
{
// The field is already a SCO wrapper, so just copy the new values to it
sco = (SCO) oldValue;
}
if (cascadeAttach)
{
// Only trigger the cascade when required
if (copy)
{
// Attach copy of the SCO
sco.attachCopy(value);
}
else
{
// Attach SCO in-situ
if (sco instanceof Collection)
{
// Attach all PC elements of the collection
boolean elementsWithoutIdentity = SCOUtils.collectionHasElementsWithoutIdentity(fmd);
SCOUtils.attachForCollection(smAttached, ((Collection)sco).toArray(), elementsWithoutIdentity);
sco.unsetOwner();
}
else if (sco instanceof Map)
{
// Attach all PC keys/values of the map
boolean keysWithoutIdentity = SCOUtils.mapHasKeysWithoutIdentity(fmd);
boolean valuesWithoutIdentity = SCOUtils.mapHasValuesWithoutIdentity(fmd);
SCOUtils.attachForMap(smAttached, ((Map)sco).entrySet(), keysWithoutIdentity, valuesWithoutIdentity);
sco.unsetOwner();
}
else
{
// Initialise the SCO with the new value
sco.initialise(value, false, false);
}
}
}
if (dirtyFields[fieldNumber] || !persistent)
{
smAttached.makeDirty(fieldNumber);
}
}
}
else if (api.isPersistable(value))
{
// Field containing PC object
if (cascadeAttach)
{
// Determine if field is "second-class" (no identity) - if has "embedded" info or serialised