Search in sources :

Example 31 with DNStateManager

use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.

the class PersistableMapping method setObjectAsValue.

/**
 * Method to set an object reference (FK) in the datastore.
 * @param ec The ExecutionContext
 * @param ps The Prepared Statement
 * @param param The parameter ids in the statement
 * @param value The value to put in the statement at these ids
 * @param ownerSM StateManager for the owner object
 * @param ownerFieldNumber Field number of this PC object in the owner
 * @throws NotYetFlushedException Just put "null" in and throw "NotYetFlushedException", to be caught by ParameterSetter and will signal to the
 *     PC object being inserted that it needs to inform this object when it is inserted.
 */
private void setObjectAsValue(ExecutionContext ec, PreparedStatement ps, int[] param, Object value, DNStateManager ownerSM, int ownerFieldNumber) {
    Object id;
    ApiAdapter api = ec.getApiAdapter();
    if (!api.isPersistable(value)) {
        throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal();
    }
    DNStateManager valueSM = ec.findStateManager(value);
    try {
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        // Check if the field is attributed in the datastore
        boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(ec.getMetaDataManager(), storeMgr, clr);
        boolean inserted = false;
        if (ownerFieldNumber >= 0) {
            // Field mapping : is this field of the related object present in the datastore?
            inserted = storeMgr.isObjectInserted(valueSM, ownerFieldNumber);
        } else if (mmd == null) {
            // Identity mapping : is the object inserted far enough to be considered of this mapping type?
            inserted = storeMgr.isObjectInserted(valueSM, type);
        }
        if (valueSM != null) {
            if (ec.getApiAdapter().isDetached(value) && valueSM.getReferencedPC() != null && ownerSM != null && mmd != null) {
                // Still detached but started attaching so replace the field with what will be the attached
                // Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table
                // mapping
                ownerSM.replaceFieldMakeDirty(ownerFieldNumber, valueSM.getReferencedPC());
            }
            if (valueSM.isWaitingToBeFlushedToDatastore()) {
                try {
                    // Related object is not yet flushed to the datastore so flush it so we can set the FK
                    valueSM.flush();
                } catch (NotYetFlushedException nfe) {
                    // Could not flush it, maybe it has a relation to this object! so set as null TODO check nullability
                    if (ownerSM != null) {
                        ownerSM.updateFieldAfterInsert(value, ownerFieldNumber);
                    }
                    setObjectAsNull(ec, ps, param);
                    return;
                }
            }
        } else {
            if (ec.getApiAdapter().isDetached(value)) {
                // Field value is detached and not yet started attaching, so attach
                Object attachedValue = ec.persistObjectInternal(value, null, -1, PersistableObjectType.PC);
                if (attachedValue != value && ownerSM != null) {
                    // Replace the field value if using copy-on-attach
                    ownerSM.replaceFieldMakeDirty(ownerFieldNumber, attachedValue);
                    // Work from attached value now that it is attached
                    value = attachedValue;
                }
                valueSM = ec.findStateManager(value);
            }
        }
        // 5) the value is the same object as we are inserting anyway and has its identity set
        if (inserted || !ec.isInserting(value) || (!hasDatastoreAttributedPrimaryKeyValues && (this.mmd != null && this.mmd.isPrimaryKey())) || (!hasDatastoreAttributedPrimaryKeyValues && ownerSM == valueSM && api.getIdForObject(value) != null)) {
            // The PC is either already inserted, or inserted down to the level we need, or not inserted at all,
            // or the field is a PK and identity not attributed by the datastore
            // Object either already exists, or is not yet being inserted.
            id = api.getIdForObject(value);
            // Check if the persistable object exists in this datastore
            boolean requiresPersisting = false;
            if (ec.getApiAdapter().isDetached(value) && ownerSM != null) {
                // Detached object so needs attaching
                if (ownerSM.isInserting()) {
                    // we can just return the value now and attach later (in InsertRequest)
                    if (!ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
                        if (ec.getObjectFromCache(api.getIdForObject(value)) != null) {
                        // Object is in cache so exists for this datastore, so no point checking
                        } else {
                            try {
                                Object obj = ec.findObject(api.getIdForObject(value), true, false, value.getClass().getName());
                                if (obj != null) {
                                    // Make sure this object is not retained in cache etc
                                    DNStateManager sm = ec.findStateManager(obj);
                                    if (sm != null) {
                                        ec.evictFromTransaction(sm);
                                    }
                                    ec.removeObjectFromLevel1Cache(api.getIdForObject(value));
                                }
                            } catch (NucleusObjectNotFoundException onfe) {
                                // Object doesn't yet exist
                                requiresPersisting = true;
                            }
                        }
                    }
                } else {
                    requiresPersisting = true;
                }
            } else if (id == null) {
                // Transient object, so we need to persist it
                requiresPersisting = true;
            } else {
                ExecutionContext pcEC = ec.getApiAdapter().getExecutionContext(value);
                if (pcEC != null && ec != pcEC) {
                    throw new NucleusUserException(Localiser.msg("041015"), id);
                }
            }
            if (requiresPersisting) {
                // This PC object needs persisting (new or detached) to do the "set"
                if (mmd != null && !mmd.isCascadePersist() && !ec.getApiAdapter().isDetached(value)) {
                    // Related PC object not persistent, but cant do cascade-persist so throw exception
                    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                        NucleusLogger.PERSISTENCE.debug(Localiser.msg("007006", mmd.getFullFieldName()));
                    }
                    throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), value);
                }
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", ownerSM != null ? IdentityUtils.getPersistableIdentityForId(ownerSM.getInternalObjectId()) : id, mmd != null ? mmd.getFullFieldName() : null));
                }
                try {
                    Object pcNew = ec.persistObjectInternal(value, null, -1, PersistableObjectType.PC);
                    if (hasDatastoreAttributedPrimaryKeyValues) {
                        ec.flushInternal(false);
                    }
                    id = api.getIdForObject(pcNew);
                    if (ec.getApiAdapter().isDetached(value) && ownerSM != null && mmd != null) {
                        // Update any detached reference to refer to the attached variant
                        ownerSM.replaceFieldMakeDirty(ownerFieldNumber, pcNew);
                        RelationType relationType = mmd.getRelationType(clr);
                        if (relationType == RelationType.MANY_TO_ONE_BI) {
                            // TODO Update the container to refer to the attached object
                            if (NucleusLogger.PERSISTENCE.isInfoEnabled()) {
                                NucleusLogger.PERSISTENCE.info("PCMapping.setObject : object " + ownerSM.getInternalObjectId() + " has field " + ownerFieldNumber + " that is 1-N bidirectional." + " Have just attached the N side so should really update the reference in the 1 side collection" + " to refer to this attached object. Not yet implemented");
                            }
                        } else if (relationType == RelationType.ONE_TO_ONE_BI) {
                            AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                            // TODO Cater for more than 1 related field
                            DNStateManager relatedSM = ec.findStateManager(pcNew);
                            relatedSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), ownerSM.getObject());
                        }
                    }
                } catch (NotYetFlushedException e) {
                    setObjectAsNull(ec, ps, param);
                    throw new NotYetFlushedException(value);
                }
            }
            if (valueSM != null) {
                valueSM.setStoringPC();
            }
            // If the field doesn't map to any columns (e.g remote FK), omit the set process
            if (getNumberOfColumnMappings() > 0) {
                if (IdentityUtils.isDatastoreIdentity(id)) {
                    Object idKey = IdentityUtils.getTargetKeyForDatastoreIdentity(id);
                    try {
                        // Try as a Long
                        getColumnMapping(0).setObject(ps, param[0], idKey);
                    } catch (Exception e) {
                        // Must be a String
                        getColumnMapping(0).setObject(ps, param[0], idKey.toString());
                    }
                } else {
                    boolean fieldsSet = false;
                    if (IdentityUtils.isSingleFieldIdentity(id) && javaTypeMappings.length > 1) {
                        Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(id);
                        AbstractClassMetaData keyCmd = ec.getMetaDataManager().getMetaDataForClass(key.getClass(), clr);
                        if (keyCmd != null && keyCmd.getIdentityType() == IdentityType.NONDURABLE) {
                            // Embedded ID - Make sure these are called starting at lowest first, in order
                            // We cannot just call SM.provideFields with all fields since that does last first
                            DNStateManager keySM = ec.findStateManager(key);
                            int[] fieldNums = keyCmd.getAllMemberPositions();
                            FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                            for (int i = 0; i < fieldNums.length; i++) {
                                keySM.provideFields(new int[] { fieldNums[i] }, fm);
                            }
                            fieldsSet = true;
                        }
                    }
                    if (!fieldsSet) {
                        // Copy PK fields from identity to the object
                        FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                        api.copyKeyFieldsFromIdToObject(value, new AppIdObjectIdFieldConsumer(api, fm), id);
                    }
                }
            }
        } else {
            if (valueSM != null) {
                valueSM.setStoringPC();
            }
            if (getNumberOfColumnMappings() > 0) {
                // Object is in the process of being inserted so we cant use its id currently and we need to store
                // a foreign key to it (which we cant yet do). Just put "null" in and throw "NotYetFlushedException",
                // to be caught by ParameterSetter and will signal to the PC object being inserted that it needs
                // to inform this object when it is inserted.
                setObjectAsNull(ec, ps, param);
                throw new NotYetFlushedException(value);
            }
        }
    } finally {
        if (valueSM != null) {
            valueSM.unsetStoringPC();
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) SingleValueFieldManager(org.datanucleus.store.fieldmanager.SingleValueFieldManager) FieldManager(org.datanucleus.store.fieldmanager.FieldManager) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) NucleusException(org.datanucleus.exceptions.NucleusException) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) DNStateManager(org.datanucleus.state.DNStateManager) NucleusException(org.datanucleus.exceptions.NucleusException) AppIdObjectIdFieldConsumer(org.datanucleus.state.AppIdObjectIdFieldConsumer)

Example 32 with DNStateManager

use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.

the class AbstractContainerMapping method setObject.

/**
 * Method to set a field in the passed JDBC PreparedStatement using this mapping.
 * Only valid when the collection is serialised.
 * @param ec ExecutionContext
 * @param ps The JDBC Prepared Statement to be populated
 * @param exprIndex The parameter positions in the JDBC statement to populate.
 * @param value The value to populate into it
 */
public void setObject(ExecutionContext ec, PreparedStatement ps, int[] exprIndex, Object value) {
    if (mmd == null || !containerIsStoredInSingleColumn()) {
        throw new NucleusException(failureMessage("setObject")).setFatal();
    }
    DNStateManager[] sms = null;
    ApiAdapter api = ec.getApiAdapter();
    if (value != null) {
        Collection smsColl = null;
        if (value instanceof java.util.Collection) {
            Iterator elementsIter = ((java.util.Collection) value).iterator();
            while (elementsIter.hasNext()) {
                Object elem = elementsIter.next();
                if (api.isPersistable(elem)) {
                    DNStateManager sm = ec.findStateManager(elem);
                    if (sm != null) {
                        if (smsColl == null) {
                            smsColl = new HashSet();
                        }
                        smsColl.add(sm);
                    }
                }
            }
        } else if (value instanceof java.util.Map) {
            Iterator entriesIter = ((java.util.Map) value).entrySet().iterator();
            while (entriesIter.hasNext()) {
                Map.Entry entry = (Map.Entry) entriesIter.next();
                Object key = entry.getKey();
                Object val = entry.getValue();
                if (api.isPersistable(key)) {
                    DNStateManager sm = ec.findStateManager(key);
                    if (sm != null) {
                        if (smsColl == null) {
                            smsColl = new HashSet();
                        }
                        smsColl.add(sm);
                    }
                }
                if (api.isPersistable(val)) {
                    DNStateManager sm = ec.findStateManager(val);
                    if (sm != null) {
                        if (smsColl == null) {
                            smsColl = new HashSet();
                        }
                        smsColl.add(sm);
                    }
                }
            }
        }
        if (smsColl != null) {
            sms = (DNStateManager[]) smsColl.toArray(new DNStateManager[smsColl.size()]);
        }
    }
    if (sms != null) {
        // Set all PC objects as being stored (so we dont detach them in any serialisation process)
        for (int i = 0; i < sms.length; i++) {
            sms[i].setStoringPC();
        }
    }
    getColumnMapping(0).setObject(ps, exprIndex[0], value);
    if (sms != null) {
        // Unset all PC objects now they are stored
        for (int i = 0; i < sms.length; i++) {
            sms[i].unsetStoringPC();
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) Map(java.util.Map) Iterator(java.util.Iterator) Collection(java.util.Collection) DNStateManager(org.datanucleus.state.DNStateManager) NucleusException(org.datanucleus.exceptions.NucleusException) Map(java.util.Map) HashSet(java.util.HashSet)

Example 33 with DNStateManager

use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.

the class CollectionMapping method postUpdate.

/**
 * Method to be called after any update of the owner class element.
 * This method could be called in two situations
 * <ul>
 * <li>Update a collection field of an object by replacing the collection with a new collection, so UpdateRequest is called, which calls here</li>
 * <li>Persist a new object, and it needed to wait til the element was inserted so goes into dirty state and then flush() triggers UpdateRequest, which comes here</li>
 * </ul>
 * @param ownerSM StateManager of the owner
 */
public void postUpdate(DNStateManager ownerSM) {
    ExecutionContext ec = ownerSM.getExecutionContext();
    Collection value = (Collection) ownerSM.provideField(getAbsoluteFieldNumber());
    if (containerIsStoredInSingleColumn()) {
        if (value != null) {
            if (mmd.getCollection().elementIsPersistent()) {
                // Make sure all persistable elements have StateManagers
                Object[] collElements = value.toArray();
                for (Object collElement : collElements) {
                    if (collElement != null) {
                        DNStateManager elemSM = ec.findStateManager(collElement);
                        if (elemSM == null || ec.getApiAdapter().getExecutionContext(collElement) == null) {
                            elemSM = ec.getNucleusContext().getStateManagerFactory().newForEmbedded(ec, collElement, false, ownerSM, mmd.getAbsoluteFieldNumber(), PersistableObjectType.EMBEDDED_COLLECTION_ELEMENT_PC);
                        }
                    }
                }
            }
        }
        return;
    }
    if (value == null) {
        // remove any elements in the collection and replace it with an empty SCO wrapper
        ((CollectionStore) storeMgr.getBackingStoreForField(ec.getClassLoaderResolver(), mmd, null)).clear(ownerSM);
        replaceFieldWithWrapper(ownerSM, null);
        return;
    }
    if (value instanceof BackedSCO) {
        // Already have a SCO value, so flush outstanding updates
        ec.flushOperationsForBackingStore(((BackedSCO) value).getBackingStore(), ownerSM);
        return;
    }
    if (mmd.isCascadePersist()) {
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("007009", IdentityUtils.getPersistableIdentityForId(ownerSM.getInternalObjectId()), mmd.getFullFieldName()));
        }
        CollectionStore backingStore = ((CollectionStore) storeMgr.getBackingStoreForField(ec.getClassLoaderResolver(), mmd, value.getClass()));
        backingStore.update(ownerSM, value);
        // Replace the field with a wrapper containing these elements
        replaceFieldWithWrapper(ownerSM, value);
    } else {
        // User doesn't want to update by reachability
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("007008", IdentityUtils.getPersistableIdentityForId(ownerSM.getInternalObjectId()), mmd.getFullFieldName()));
        }
        return;
    }
}
Also used : ExecutionContext(org.datanucleus.ExecutionContext) Collection(java.util.Collection) DNStateManager(org.datanucleus.state.DNStateManager) CollectionStore(org.datanucleus.store.types.scostore.CollectionStore) BackedSCO(org.datanucleus.store.types.wrappers.backed.BackedSCO)

Example 34 with DNStateManager

use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.

the class CollectionMapping method postInsert.

// --------------- Implementation of MappingCallbacks -------------------
/**
 * Method to be called after the insert of the owner class element.
 * @param ownerSM StateManager of the owner
 */
public void postInsert(DNStateManager ownerSM) {
    ExecutionContext ec = ownerSM.getExecutionContext();
    Collection value = (Collection) ownerSM.provideField(getAbsoluteFieldNumber());
    if (containerIsStoredInSingleColumn()) {
        if (value != null) {
            if (mmd.getCollection().elementIsPersistent()) {
                // Make sure all persistable elements have StateManagers
                Object[] collElements = value.toArray();
                for (Object elem : collElements) {
                    if (elem != null) {
                        DNStateManager elemSM = ec.findStateManager(elem);
                        if (elemSM == null || ec.getApiAdapter().getExecutionContext(elem) == null) {
                            elemSM = ec.getNucleusContext().getStateManagerFactory().newForEmbedded(ec, elem, false, ownerSM, mmd.getAbsoluteFieldNumber(), PersistableObjectType.EMBEDDED_COLLECTION_ELEMENT_PC);
                        }
                    }
                }
            }
        }
        return;
    }
    if (value == null) {
        // replace null collections with an empty SCO wrapper
        replaceFieldWithWrapper(ownerSM, null);
        return;
    }
    Object[] collElements = value.toArray();
    if (!mmd.isCascadePersist()) {
        // Check that all elements are persistent before continuing and throw exception if necessary
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("007006", mmd.getFullFieldName()));
        }
        for (Object collElement : collElements) {
            if (!ec.getApiAdapter().isDetached(collElement) && !ec.getApiAdapter().isPersistent(collElement)) {
                // Element is not persistent so throw exception
                throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), collElement);
            }
        }
    } else {
        // Reachability
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", IdentityUtils.getPersistableIdentityForId(ownerSM.getInternalObjectId()), mmd.getFullFieldName()));
        }
    }
    // Check if some elements need attaching
    // TODO Investigate if we can just use the attachCopy route below and skip off this check
    boolean needsAttaching = false;
    for (Object collElement : collElements) {
        if (ec.getApiAdapter().isDetached(collElement)) {
            needsAttaching = true;
            break;
        }
    }
    if (needsAttaching) {
        // Create a wrapper and attach the elements (and add the others)
        SCO collWrapper = replaceFieldWithWrapper(ownerSM, null);
        if (value.size() > 0) {
            collWrapper.attachCopy(value);
            // The attach will have put entries in the operationQueue if using optimistic, so flush them
            ec.flushOperationsForBackingStore(((BackedSCO) collWrapper).getBackingStore(), ownerSM);
        }
    } else {
        if (value.size() > 0) {
            // Add the elements direct to the datastore
            ((CollectionStore) storeMgr.getBackingStoreForField(ec.getClassLoaderResolver(), mmd, value.getClass())).addAll(ownerSM, value, 0);
            // Create a SCO wrapper with the elements loaded
            replaceFieldWithWrapper(ownerSM, value);
        } else {
            if (mmd.getRelationType(ec.getClassLoaderResolver()) == RelationType.MANY_TO_MANY_BI) {
                // Create a SCO wrapper, pass in null so it loads any from the datastore (on other side?)
                replaceFieldWithWrapper(ownerSM, null);
            } else {
                // Create a SCO wrapper, pass in empty collection to avoid loading from DB (extra SQL)
                replaceFieldWithWrapper(ownerSM, value);
            }
        }
    }
}
Also used : ExecutionContext(org.datanucleus.ExecutionContext) Collection(java.util.Collection) DNStateManager(org.datanucleus.state.DNStateManager) CollectionStore(org.datanucleus.store.types.scostore.CollectionStore) SCO(org.datanucleus.store.types.SCO) BackedSCO(org.datanucleus.store.types.wrappers.backed.BackedSCO) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException)

Example 35 with DNStateManager

use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.

the class EmbeddedMapping method getObject.

/**
 * Accessor for the embedded object from the result set
 * @param ec ExecutionContext
 * @param rs The ResultSet
 * @param ownerSM StateManager of the owning object containing this embedded object
 * @param ownerFieldNumber Field number in the owning object where this is stored
 * @param param Array of param numbers in the ResultSet for the fields of this object
 * @return The embedded object
 */
@Override
public Object getObject(ExecutionContext ec, ResultSet rs, int[] param, DNStateManager ownerSM, int ownerFieldNumber) {
    Object value = null;
    // Determine the type of the embedded object
    AbstractClassMetaData embCmd = this.embCmd;
    int n = 0;
    if (discrimMapping != null) {
        Object discrimValue = discrimMapping.getObject(ec, rs, new int[] { param[n] });
        String className = ec.getMetaDataManager().getClassNameFromDiscriminatorValue((String) discrimValue, discrimMetaData);
        embCmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr);
        n++;
    }
    // Create a persistable to put the values into
    DNStateManager embSM = ec.getNucleusContext().getStateManagerFactory().newForEmbedded(ec, embCmd, ownerSM, mmd.getAbsoluteFieldNumber(), objectType);
    value = embSM.getObject();
    String nullColumn = (emd != null) ? emd.getNullIndicatorColumn() : null;
    String nullValue = (emd != null) ? emd.getNullIndicatorValue() : null;
    // Populate the field values
    int numJavaMappings = javaTypeMappings.size();
    for (int i = 0; i < numJavaMappings; i++) {
        JavaTypeMapping mapping = javaTypeMappings.get(i);
        int embAbsFieldNum = embCmd.getAbsolutePositionOfMember(mapping.getMemberMetaData().getName());
        if (embAbsFieldNum >= 0) {
            // Mapping for field that is present in this embedded type, so set the field
            if (mapping instanceof EmbeddedPCMapping) {
                // We have a nested embedded
                int numSubParams = mapping.getNumberOfColumnMappings();
                int[] subParam = new int[numSubParams];
                int k = 0;
                for (int j = n; j < n + numSubParams; j++) {
                    subParam[k++] = param[j];
                }
                n += numSubParams;
                // Use the sub-object mapping to extract the value for that object
                Object subValue = mapping.getObject(ec, rs, subParam, embSM, embAbsFieldNum);
                if (subValue != null) {
                    embSM.replaceField(embAbsFieldNum, subValue);
                }
            // TODO Check the null column and its value in the sub-embedded ?
            } else {
                if (mapping.getNumberOfColumnMappings() > 0) {
                    // Extract the value(s) for this field and update the PC if it is not null
                    int[] posMapping = new int[mapping.getNumberOfColumnMappings()];
                    for (int j = 0; j < posMapping.length; j++) {
                        posMapping[j] = param[n++];
                    }
                    Object fieldValue = mapping.getObject(ec, rs, posMapping);
                    // Check for the null column and its value and break if this matches the null check
                    if (nullColumn != null && mapping.getMemberMetaData().getColumnMetaData()[0].getName().equals(nullColumn)) {
                        if ((nullValue == null && fieldValue == null) || (nullValue != null && fieldValue != null && fieldValue.toString().equals(nullValue))) {
                            value = null;
                            break;
                        }
                    }
                    // Set the field value
                    if (fieldValue != null) {
                        embSM.replaceField(embAbsFieldNum, fieldValue);
                    } else {
                        // If the value is null, but the field is not a primitive update it
                        AbstractMemberMetaData embFmd = embCmd.getMetaDataForManagedMemberAtAbsolutePosition(embAbsFieldNum);
                        if (!embFmd.getType().isPrimitive()) {
                            embSM.replaceField(embAbsFieldNum, fieldValue);
                        }
                    }
                }
            }
        } else {
            // Mapping not present in this embedded type so maybe subclass, so just omit the positions
            int numSubParams = mapping.getNumberOfColumnMappings();
            n += numSubParams;
        }
    }
    // Update owner field in the element (if present)
    if (emd != null) {
        String ownerField = emd.getOwnerMember();
        if (ownerField != null) {
            int ownerFieldNumberInElement = embCmd.getAbsolutePositionOfMember(ownerField);
            if (ownerFieldNumberInElement >= 0) {
                embSM.replaceField(ownerFieldNumberInElement, ownerSM != null ? ownerSM.getObject() : null);
            }
        }
    }
    return value;
}
Also used : DNStateManager(org.datanucleus.state.DNStateManager) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Aggregations

DNStateManager (org.datanucleus.state.DNStateManager)64 ExecutionContext (org.datanucleus.ExecutionContext)38 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)22 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)20 SQLException (java.sql.SQLException)17 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)16 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)15 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)15 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)14 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)14 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)13 SQLController (org.datanucleus.store.rdbms.SQLController)13 PreparedStatement (java.sql.PreparedStatement)12 ResultSet (java.sql.ResultSet)10 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)9 NucleusException (org.datanucleus.exceptions.NucleusException)9 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)9 Collection (java.util.Collection)8 ArrayList (java.util.ArrayList)7 RelationType (org.datanucleus.metadata.RelationType)7