use of org.datanucleus.store.types.scostore.PersistableRelationStore in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method postInsert.
/**
* Method executed just after the insert of the owning object, allowing any necessary action
* to this field and the object stored in it.
* @param op ObjectProvider for the owner
*/
public void postInsert(ObjectProvider op) {
Object pc = op.provideField(mmd.getAbsoluteFieldNumber());
TypeManager typeManager = op.getExecutionContext().getTypeManager();
pc = mmd.isSingleCollection() ? singleCollectionValue(typeManager, pc) : pc;
if (pc == null) {
// Has been set to null so nothing to do
return;
}
ClassLoaderResolver clr = op.getExecutionContext().getClassLoaderResolver();
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_BI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
return;
}
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, op.getObject(), pc);
if (relatedMmd == null) {
// Fsck knows why
throw new NucleusUserException("You have a field " + mmd.getFullFieldName() + " that is 1-1 bidir yet cannot find the equivalent field at the other side. Why is that?");
}
Object relatedValue = otherOP.provideField(relatedMmd.getAbsoluteFieldNumber());
relatedValue = relatedMmd.isSingleCollection() ? singleCollectionValue(typeManager, relatedValue) : relatedValue;
if (relatedValue == null) {
// Managed Relations : Other side not set so update it in memory
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041018", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName()));
}
Object replaceValue = op.getObject();
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = typeManager.getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(relatedMmd, op.getObject());
}
otherOP.replaceField(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
} else if (relatedValue != op.getObject()) {
// Managed Relations : Other side is inconsistent so throw exception
throw new NucleusUserException(Localiser.msg("041020", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(relatedValue)));
}
} else if (relationType == RelationType.MANY_TO_ONE_BI && relatedMmds[0].hasCollection()) {
// TODO Make sure we have this PC in the collection at the other side
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP != null) {
// Managed Relations : add to the collection on the other side
Collection relatedColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (relatedColl != null && !(relatedColl instanceof SCOCollection)) {
// TODO Make sure the collection is a wrapper
boolean contained = relatedColl.contains(op.getObject());
if (!contained) {
NucleusLogger.PERSISTENCE.info(Localiser.msg("041022", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmds[0].getFullFieldName()));
// TODO Enable this. Currently causes issues with PMImplTest, InheritanceStrategyTest, TCK "inheritance1.conf"
/*relatedColl.add(op.getObject());*/
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
// Related object is not yet persisted so persist it
Object other = op.getExecutionContext().persistObjectInternal(pc, null, -1, ObjectProvider.PC);
otherOP = op.getExecutionContext().findObjectProvider(other);
}
// Add join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.add(op, otherOP);
}
}
use of org.datanucleus.store.types.scostore.PersistableRelationStore in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method preDelete.
/**
* Method executed just before the owning object is deleted, allowing tidying up of any relation information.
* @param op ObjectProvider for the owner
*/
public void preDelete(ObjectProvider op) {
int fieldNumber = mmd.getAbsoluteFieldNumber();
if (!op.isFieldLoaded(fieldNumber)) {
// makes sure field is loaded
try {
op.loadField(fieldNumber);
} catch (NucleusObjectNotFoundException onfe) {
// Already deleted so just return
return;
}
}
Object pc = op.provideField(fieldNumber);
pc = mmd.isSingleCollection() ? SCOUtils.singleCollectionValue(getStoreManager().getNucleusContext().getTypeManager(), pc) : pc;
if (pc == null) {
// Null value so nothing to do
return;
}
ExecutionContext ec = op.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
// N-1 Uni, so delete join table entry
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.remove(op);
}
// Check if we should delete the related object when this object is deleted
boolean dependent = mmd.isDependent();
if (mmd.isCascadeRemoveOrphans()) {
// JPA allows "orphan removal" to define deletion of the other side
dependent = true;
}
// Check if the field has a FK defined
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 (RelationType.isBidirectional(relationType) && relatedMmds[0].getForeignKeyMetaData() != null) {
hasFK = true;
}
if (ec.getStringProperty(PropertyNames.PROPERTY_DELETION_POLICY).equals("JDO2")) {
// JDO doesn't currently take note of foreign-key
hasFK = false;
}
}
// There may be some corner cases that this code doesn't yet cater for
if (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.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, but the field is nullable so 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
op.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(op, 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 on other object
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("041017", StringUtils.toJVMIDString(op.getObject()), mmd.getFullFieldName()));
}
}
} else {
// We're deleting the FK at this side so shouldn't be an issue
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, op.getObject(), pc);
if (relatedMmd != null) {
ObjectProvider otherOP = ec.findObjectProvider(pc);
if (otherOP != null) {
// Managed Relations : 1-1 bidir, so null out the object at the other
Object currentValue = otherOP.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentValue != null) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041019", StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName(), op.getObjectAsPrintable()));
}
otherOP.replaceFieldMakeDirty(relatedMmd.getAbsoluteFieldNumber(), null);
if (ec.getManageRelations()) {
otherOP.getExecutionContext().getRelationshipManager(otherOP).relationChange(relatedMmd.getAbsoluteFieldNumber(), op.getObject(), null);
}
}
}
}
}
} else if (relationType == RelationType.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 otherOP = ec.findObjectProvider(pc);
if (dependent) {
if (isNullable) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherOP.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherOP, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
}
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else if (!hasFK) {
if (isNullable()) {
Object currentRelatedValue = otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (currentRelatedValue != null) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherOP.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherOP, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
// Managed Relations : 1-1 bidir, so null out the object at the other
if (ec.getManageRelations()) {
otherOP.getExecutionContext().getRelationshipManager(otherOP).relationChange(relatedMmds[0].getAbsoluteFieldNumber(), op.getObject(), null);
}
}
} else {
// TODO Remove it
}
} else {
// User has a FK defined (in MetaData) so let the datastore take care of it
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
ObjectProvider otherOP = ec.findObjectProvider(pc);
if (relatedMmds[0].getJoinMetaData() == null) {
// N-1 with FK at this side
if (otherOP.isDeleting()) {
// Other object is being deleted too but this side has the FK so just delete this object
} else {
// Other object is not being deleted so delete it if necessary
if (dependent) {
if (isNullable()) {
// TODO Datastore nullability info can be unreliable so try to avoid this call
// Null out the FK in the datastore using a direct update (since we are deleting)
op.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(op, new int[] { fieldNumber });
}
if (ec.getApiAdapter().isDeleted(pc)) {
// Object is already tagged for deletion but we're deleting the FK so leave til flush()
} else {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherOP.getObject()) && !otherOP.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherOP, false);
// Make sure collection field is loaded
otherOP.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null) {
if (ec.getManageRelations()) {
otherOP.getExecutionContext().getRelationshipManager(otherOP).relationRemove(relatedMmds[0].getAbsoluteFieldNumber(), op.getObject());
}
// TODO Localise this message
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(op.getObject());
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else {
// N-1 with join table so no FK here so need to remove from Collection/Map first? (managed relations)
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherOP.getObject()) && !otherOP.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherOP, false);
// Make sure the other object has the collection loaded so does this change
otherOP.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null) {
// TODO Localise this
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(op.getObject());
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
// N-1 uni with join table
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// No relation so what is this field ?
}
}
use of org.datanucleus.store.types.scostore.PersistableRelationStore in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method postUpdate.
/**
* Method executed just afer any update of the owning object, allowing any necessary action to this field and the object stored in it.
* @param op ObjectProvider for the owner
*/
public void postUpdate(ObjectProvider op) {
Object pc = op.provideField(mmd.getAbsoluteFieldNumber());
pc = mmd.isSingleCollection() ? SCOUtils.singleCollectionValue(getStoreManager().getNucleusContext().getTypeManager(), pc) : pc;
ClassLoaderResolver clr = op.getExecutionContext().getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
if (pc == null) {
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.remove(op);
}
return;
}
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
if (relationType == RelationType.ONE_TO_ONE_BI || relationType == RelationType.MANY_TO_ONE_BI || relationType == RelationType.MANY_TO_ONE_UNI) {
// Related object is not yet persisted (e.g 1-1 with FK at other side) so persist it
Object other = op.getExecutionContext().persistObjectInternal(pc, null, -1, ObjectProvider.PC);
otherOP = op.getExecutionContext().findObjectProvider(other);
}
}
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.update(op, otherOP);
}
}
Aggregations