Search in sources :

Example 31 with RelationType

use of org.datanucleus.metadata.RelationType in project datanucleus-rdbms by datanucleus.

the class ParameterSetter method storeObjectField.

public void storeObjectField(int fieldNumber, Object value) {
    StatementMappingIndex mapIdx = stmtMappings.getMappingForMemberPosition(fieldNumber);
    if (value == null && mapIdx.getMapping().getMemberMetaData().getNullValue() == NullValue.EXCEPTION) {
        throw new NucleusUserException(Localiser.msg("052400", mapIdx.getMapping().getMemberMetaData().getFullFieldName()));
    }
    try {
        JavaTypeMapping mapping = mapIdx.getMapping();
        boolean provideOwner = false;
        if (mapping instanceof EmbeddedPCMapping || mapping instanceof SerialisedPCMapping || mapping instanceof SerialisedReferenceMapping || mapping instanceof PersistableMapping || mapping instanceof InterfaceMapping) {
            // Pass in the owner ObjectProvider/field for any mappings that have relations
            provideOwner = true;
        }
        if (mapIdx.getNumberOfParameterOccurrences() > 0) {
            for (int i = 0; i < mapIdx.getNumberOfParameterOccurrences(); i++) {
                // Set this value for all occurrences of this parameter
                if (provideOwner) {
                    mapping.setObject(ec, statement, mapIdx.getParameterPositionsForOccurrence(i), value, op, fieldNumber);
                } else {
                    mapping.setObject(ec, statement, mapIdx.getParameterPositionsForOccurrence(i), value);
                }
            }
        } else {
            // Important : call setObject even if the paramIndices is null (reachability)
            if (provideOwner) {
                mapping.setObject(ec, statement, null, value, op, fieldNumber);
            } else {
                mapping.setObject(ec, statement, null, value);
            }
        }
        AbstractMemberMetaData mmd = op.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
        if (op.getClassMetaData().getSCOMutableMemberFlags()[fieldNumber]) {
            SCOUtils.wrapSCOField(op, fieldNumber, value, true);
        } else if (RelationType.isRelationSingleValued(relationType) && (mmd.getEmbeddedMetaData() != null && mmd.getEmbeddedMetaData().getOwnerMember() != null)) {
            // Embedded PC, so make sure the field is wrapped where appropriate TODO This should be part of ManagedRelationships
            op.updateOwnerFieldInEmbeddedField(fieldNumber, value);
        }
    } catch (NotYetFlushedException e) {
        if (op.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber).getNullValue() == NullValue.EXCEPTION) {
            throw e;
        }
        op.updateFieldAfterInsert(e.getPersistable(), fieldNumber);
    }
}
Also used : InterfaceMapping(org.datanucleus.store.rdbms.mapping.java.InterfaceMapping) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SerialisedReferenceMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedReferenceMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) EmbeddedPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) RelationType(org.datanucleus.metadata.RelationType) SerialisedPCMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedPCMapping) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 32 with RelationType

use of org.datanucleus.metadata.RelationType in project datanucleus-rdbms by datanucleus.

the class ResultSetGetter method fetchObjectField.

public Object fetchObjectField(int fieldNumber) {
    StatementMappingIndex mapIdx = resultMappings.getMappingForMemberPosition(fieldNumber);
    JavaTypeMapping mapping = mapIdx.getMapping();
    AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
    RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
    Object value;
    if (mapping instanceof EmbeddedPCMapping || mapping instanceof SerialisedPCMapping || mapping instanceof SerialisedReferenceMapping) {
        value = mapping.getObject(ec, rs, mapIdx.getColumnPositions(), op, fieldNumber);
    } else {
        if (mmd.isSingleCollection()) {
            StatementClassMapping relationMappings = resultMappings.getMappingDefinitionForMemberPosition(fieldNumber);
            if (relationMappings != null) {
                Class type = ec.getClassLoaderResolver().classForName(mmd.getCollection().getElementType());
                value = processSubObjectFields(mapping, type, relationMappings);
                ElementContainerHandler containerHandler = ec.getTypeManager().getContainerHandler(mmd.getType());
                value = containerHandler.newContainer(mmd, value);
            } else {
                value = mapping.getObject(ec, rs, mapIdx.getColumnPositions());
            }
        } else if (RelationType.isRelationSingleValued(relationType)) {
            // Process fields of sub-object if available in this result set
            StatementClassMapping relationMappings = resultMappings.getMappingDefinitionForMemberPosition(fieldNumber);
            if (relationMappings != null) {
                value = processSubObjectFields(mapping, mmd.getType(), relationMappings);
            } else {
                value = mapping.getObject(ec, rs, mapIdx.getColumnPositions());
            }
        } else {
            value = mapping.getObject(ec, rs, mapIdx.getColumnPositions());
        }
    }
    if (op != null) {
        if (cmd.getSCOMutableMemberFlags()[fieldNumber]) {
            // Wrap any SCO mutable fields
            return SCOUtils.wrapSCOField(op, fieldNumber, value, false);
        } else if (RelationType.isRelationSingleValued(relationType) && (mmd.getEmbeddedMetaData() != null && mmd.getEmbeddedMetaData().getOwnerMember() != null)) {
            // Embedded PC, so make sure the field is wrapped where appropriate TODO This should be part of ManagedRelationships
            op.updateOwnerFieldInEmbeddedField(fieldNumber, value);
            return value;
        }
    }
    return value;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SerialisedReferenceMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedReferenceMapping) EmbeddedPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping) RelationType(org.datanucleus.metadata.RelationType) SerialisedPCMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedPCMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping)

Example 33 with RelationType

use of org.datanucleus.metadata.RelationType in project datanucleus-core by datanucleus.

the class RelationshipManagerImpl method relationChange.

/* (non-Javadoc)
     * @see org.datanucleus.state.RelationshipManager#relationChange(int, java.lang.Object, java.lang.Object)
     */
public void relationChange(int fieldNumber, Object oldValue, Object newValue) {
    if (ec.isManagingRelations()) {
        return;
    }
    Integer fieldKey = Integer.valueOf(fieldNumber);
    List<RelationChange> changes = fieldChanges.get(fieldKey);
    if (changes == null) {
        changes = new ArrayList<RelationChange>();
        fieldChanges.put(fieldKey, changes);
    }
    AbstractMemberMetaData mmd = ownerOP.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
    RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
    if (relationType == RelationType.ONE_TO_ONE_BI || relationType == RelationType.MANY_TO_ONE_BI) {
        // TODO If this field is changed multiple times, we don't currently handle it e.g "myObj.setX(null);" followed by "myObj.setX(newX);"
        if (changes.isEmpty()) {
            changes.add(new RelationChange(ChangeType.CHANGE_OBJECT, newValue, oldValue));
        }
        return;
    }
    if (relationType == RelationType.ONE_TO_MANY_BI || relationType == RelationType.MANY_TO_MANY_BI) {
        // TODO What about Map?
        if (mmd.hasCollection()) {
            Collection oldColl = (Collection) oldValue;
            Collection newColl = (Collection) newValue;
            if (oldColl == null) {
                if (newColl != null) {
                    // Add all elements
                    for (Object newElem : newColl) {
                        changes.add(new RelationChange(ChangeType.ADD_OBJECT, newElem));
                    }
                }
            } else {
                if (newColl == null) {
                    AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(ec.getClassLoaderResolver())[0];
                    for (Object element : oldColl) {
                        if (ownerOP.getLifecycleState().isDeleted) {
                            // Deleting the owner, so register the element to reset its owner
                            ec.removeObjectFromLevel2Cache(ec.getApiAdapter().getIdForObject(element));
                            ObjectProvider elementOP = ec.findObjectProvider(element);
                            if (relationType == RelationType.ONE_TO_MANY_BI) {
                                // TODO This needs marking as a secondary change. i.e we dont want follow on checks, just null out the relation during process()
                                ec.getRelationshipManager(elementOP).relationChange(relatedMmd.getAbsoluteFieldNumber(), ownerOP.getObject(), null);
                            } else if (relationType == RelationType.MANY_TO_MANY_BI) {
                                // TODO This needs marking as a secondary change. i.e we don't want follow on checks, just remove the element from the relation during process()
                                ec.getRelationshipManager(elementOP).relationRemove(relatedMmd.getAbsoluteFieldNumber(), ownerOP.getObject());
                            }
                        } else {
                            // Remove the element
                            changes.add(new RelationChange(ChangeType.REMOVE_OBJECT, element));
                        }
                    }
                } else {
                    // Remove some and add some
                    for (Object newElem : newColl) {
                        boolean alreadyExists = false;
                        for (Object oldElem : oldColl) {
                            if (newElem == oldElem) {
                                alreadyExists = true;
                                break;
                            }
                        }
                        if (!alreadyExists) {
                            ObjectProvider elemOP = ec.findObjectProvider(newElem);
                            if (elemOP != null) {
                                AbstractMemberMetaData elemMmd = mmd.getRelatedMemberMetaData(ec.getClassLoaderResolver())[0];
                                Object oldOwner = elemOP.provideField(elemMmd.getAbsoluteFieldNumber());
                                if (!elemOP.isFieldLoaded(elemMmd.getAbsoluteFieldNumber())) {
                                    elemOP.loadField(elemMmd.getAbsoluteFieldNumber());
                                }
                                if (oldOwner != null) {
                                    // Remove from old owner collection
                                    ObjectProvider oldOwnerOP = ec.findObjectProvider(oldOwner);
                                    if (oldOwnerOP != null) {
                                        // TODO This needs marking as a secondary change. i.e we dont want follow on checks, just remove the element from the relation during process()
                                        ec.getRelationshipManager(oldOwnerOP).relationRemove(fieldNumber, newElem);
                                    }
                                }
                            }
                            relationAdd(fieldNumber, newElem);
                        }
                    }
                    for (Object oldElem : oldColl) {
                        boolean stillExists = false;
                        for (Object newElem : newColl) {
                            if (oldElem == newElem) {
                                stillExists = true;
                                break;
                            }
                        }
                        if (!stillExists) {
                            relationRemove(fieldNumber, oldElem);
                        }
                    }
                }
            }
        }
    }
}
Also used : RelationType(org.datanucleus.metadata.RelationType) Collection(java.util.Collection) SCOCollection(org.datanucleus.store.types.SCOCollection) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 34 with RelationType

use of org.datanucleus.metadata.RelationType in project datanucleus-core by datanucleus.

the class RelationshipManagerImpl method relationAdd.

/* (non-Javadoc)
     * @see org.datanucleus.state.RelationshipManager#relationAdd(int, java.lang.Object)
     */
public void relationAdd(int fieldNumber, Object val) {
    if (ec.isManagingRelations()) {
        return;
    }
    AbstractMemberMetaData mmd = ownerOP.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
    RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
    if (relationType != RelationType.ONE_TO_MANY_BI && relationType != RelationType.MANY_TO_MANY_BI) {
        return;
    }
    ObjectProvider elemOP = ec.findObjectProvider(val);
    if (elemOP != null) {
        AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(ec.getClassLoaderResolver())[0];
        if (elemOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
            Object currentOwnerId = ec.getApiAdapter().getIdForObject(elemOP.provideField(relatedMmd.getAbsoluteFieldNumber()));
            ec.removeObjectFromLevel2Cache(currentOwnerId);
        }
    }
    Integer fieldKey = Integer.valueOf(fieldNumber);
    List<RelationChange> changeList = fieldChanges.get(fieldKey);
    if (changeList == null) {
        changeList = new ArrayList();
        fieldChanges.put(fieldKey, changeList);
    }
    ec.removeObjectFromLevel2Cache(ec.getApiAdapter().getIdForObject(val));
    changeList.add(new RelationChange(ChangeType.ADD_OBJECT, val));
}
Also used : RelationType(org.datanucleus.metadata.RelationType) ArrayList(java.util.ArrayList) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 35 with RelationType

use of org.datanucleus.metadata.RelationType in project datanucleus-core by datanucleus.

the class StateManagerImpl method refreshFieldsInFetchPlan.

/**
 * Refreshes from the database all fields in fetch plan.
 * Called by life-cycle transitions when the object undergoes a "transitionRefresh".
 */
public void refreshFieldsInFetchPlan() {
    int[] fieldNumbers = myFP.getMemberNumbers();
    if (fieldNumbers != null && fieldNumbers.length > 0) {
        clearDirtyFlags(fieldNumbers);
        ClassUtils.clearFlags(loadedFields, fieldNumbers);
        // Can't refresh PK fields!
        markPKFieldsAsLoaded();
        boolean callPostLoad = myFP.isToCallPostLoadFetchPlan(this.loadedFields);
        // Refresh the fetch plan fields in this object
        // Make sure that the version is reset upon fetch
        setTransactionalVersion(null);
        loadFieldsFromDatastore(fieldNumbers);
        if (cmd.hasRelations(myEC.getClassLoaderResolver())) {
            // Check for cascade refreshes to related objects
            for (int i = 0; i < fieldNumbers.length; i++) {
                AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
                RelationType relationType = fmd.getRelationType(myEC.getClassLoaderResolver());
                if (relationType != RelationType.NONE && fmd.isCascadeRefresh()) {
                    // Need to refresh the related field object(s)
                    Object value = provideField(fieldNumbers[i]);
                    if (value != null) {
                        if (fmd.hasContainer()) {
                            // TODO This should replace the SCO wrapper with a new one, or reload the wrapper
                            ApiAdapter api = getExecutionContext().getApiAdapter();
                            ContainerHandler containerHandler = myEC.getTypeManager().getContainerHandler(fmd.getType());
                            for (Object object : containerHandler.getAdapter(value)) {
                                if (api.isPersistable(object)) {
                                    getExecutionContext().refreshObject(object);
                                }
                            }
                        } else if (value instanceof Persistable) {
                            // Refresh any PC fields
                            myEC.refreshObject(value);
                        }
                    }
                }
            }
        }
        updateLevel2CacheForFields(fieldNumbers);
        if (callPostLoad) {
            postLoad();
        }
        getCallbackHandler().postRefresh(myPC);
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) Persistable(org.datanucleus.enhancement.Persistable) RelationType(org.datanucleus.metadata.RelationType) ContainerHandler(org.datanucleus.store.types.ContainerHandler) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

RelationType (org.datanucleus.metadata.RelationType)41 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)33 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)14 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)10 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)10 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)10 ArrayList (java.util.ArrayList)9 ExecutionContext (org.datanucleus.ExecutionContext)7 ApiAdapter (org.datanucleus.api.ApiAdapter)7 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)7 ObjectProvider (org.datanucleus.state.ObjectProvider)6 Collection (java.util.Collection)5 Iterator (java.util.Iterator)5 List (java.util.List)5 NucleusException (org.datanucleus.exceptions.NucleusException)5 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 Map (java.util.Map)4 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)4 EmbeddedPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping)4