// JPA allows "orphan removal" to define deletion of the other side
dependent = true;
}
// Check if the field has a FK defined
MappedStoreManager storeMgr = (MappedStoreManager)ec.getStoreManager();
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
// TODO Cater for more than 1 related field
boolean hasFK = false;
if (!dependent)
{
// Not dependent, so check if the datastore has a FK and will take care of it for us
if (mmd.getForeignKeyMetaData() != null)
{
hasFK = true;
}
if (relatedMmds != null && relatedMmds[0].getForeignKeyMetaData() != null)
{
hasFK = true;
}
if (ec.getNucleusContext().getPersistenceConfiguration().getStringProperty("datanucleus.deletionPolicy").equals("JDO2"))
{
// JDO2 doesnt currently (2.0 spec) take note of foreign-key
hasFK = false;
}
}
// Basic rules for the following :-
// 1. If it is dependent then we delete it (maybe after nulling).
// 2. If it is not dependent and they have defined no FK then null it, else delete it
// 3. If it is not dependent and they have a FK, let the datastore handle the delete
// There may be some corner cases that this code doesn't yet cater for
if (relationType == Relation.ONE_TO_ONE_UNI ||
(relationType == Relation.ONE_TO_ONE_BI && mmd.getMappedBy() == null))
{
// 1-1 with FK at this side (owner of the relation)
if (dependent)
{
boolean relatedObjectDeleted = ec.getApiAdapter().isDeleted(pc);
if (isNullable() && !relatedObjectDeleted)
{
// Other object not yet deleted - just null out the FK
// TODO Not doing this would cause errors in 1-1 uni relations (e.g AttachDetachTest)
// TODO Log this since it affects the resultant objects
sm.replaceFieldMakeDirty(fieldNumber, null);
sm.getExecutionContext().getStoreManager().getPersistenceHandler().updateObject(sm, new int[]{fieldNumber});
if (!relatedObjectDeleted)
{
// Mark the other object for deletion since not yet tagged
ec.deleteObjectInternal(pc);
}
}
else
{
// Can't just delete the other object since that would cause a FK constraint violation
// Do nothing - handled by DeleteRequest
NucleusLogger.DATASTORE_PERSIST.warn("Delete of " + StringUtils.toJVMIDString(sm.getObject()) +
" needs delete of related object at " + mmd.getFullFieldName() + " but cannot delete it direct since FK is here");
}
}
else
{
// We're deleting the FK at this side so shouldnt be an issue
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, sm.getObject(), pc);
if (relatedMmd != null)
{
ObjectProvider otherSM = ec.findObjectProvider(pc);
if (otherSM != null)
{
// Managed Relations : 1-1 bidir, so null out the object at the other
Object currentValue = otherSM.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentValue != null)
{
if (NucleusLogger.PERSISTENCE.isDebugEnabled())
{
NucleusLogger.PERSISTENCE.debug(LOCALISER.msg("041019",
StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName(),
sm.toPrintableID()));
}
otherSM.replaceFieldMakeDirty(relatedMmd.getAbsoluteFieldNumber(), null);
if (ec.getManageRelations())
{
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationChange(
relatedMmd.getAbsoluteFieldNumber(), sm.getObject(), null);
}
}
}
}
}
}
else if (relationType == Relation.ONE_TO_ONE_BI && mmd.getMappedBy() != null)
{
// 1-1 with FK at other side
DatastoreClass relatedTable = storeMgr.getDatastoreClass(relatedMmds[0].getClassName(), clr);
JavaTypeMapping relatedMapping = relatedTable.getMemberMapping(relatedMmds[0]);
boolean isNullable = relatedMapping.isNullable();
ObjectProvider otherSM = ec.findObjectProvider(pc);
if (dependent)
{