Search in sources :

Example 1 with PersistableRelationStore

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);
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) RelationType(org.datanucleus.metadata.RelationType) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) TypeManager(org.datanucleus.store.types.TypeManager) Collection(java.util.Collection) SCOCollection(org.datanucleus.store.types.SCOCollection) SCOCollection(org.datanucleus.store.types.SCOCollection) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler) PersistableRelationStore(org.datanucleus.store.types.scostore.PersistableRelationStore)

Example 2 with PersistableRelationStore

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 ?
    }
}
Also used : ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) Collection(java.util.Collection) SCOCollection(org.datanucleus.store.types.SCOCollection) ObjectProvider(org.datanucleus.state.ObjectProvider) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) PersistableRelationStore(org.datanucleus.store.types.scostore.PersistableRelationStore)

Example 3 with PersistableRelationStore

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);
    }
}
Also used : RelationType(org.datanucleus.metadata.RelationType) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) ObjectProvider(org.datanucleus.state.ObjectProvider) PersistableRelationStore(org.datanucleus.store.types.scostore.PersistableRelationStore)

Aggregations

ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)3 RelationType (org.datanucleus.metadata.RelationType)3 ObjectProvider (org.datanucleus.state.ObjectProvider)3 PersistableRelationStore (org.datanucleus.store.types.scostore.PersistableRelationStore)3 Collection (java.util.Collection)2 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)2 SCOCollection (org.datanucleus.store.types.SCOCollection)2 ExecutionContext (org.datanucleus.ExecutionContext)1 NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)1 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)1 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)1 ElementContainerHandler (org.datanucleus.store.types.ElementContainerHandler)1 TypeManager (org.datanucleus.store.types.TypeManager)1