Search in sources :

Example 6 with SCO

use of org.datanucleus.store.types.SCO in project datanucleus-rdbms by datanucleus.

the class CollectionMapping method postInsert.

/**
 * Method to be called after the insert of the owner class element.
 * @param ownerOP ObjectProvider of the owner
 */
public void postInsert(ObjectProvider ownerOP) {
    ExecutionContext ec = ownerOP.getExecutionContext();
    Collection value = (Collection) ownerOP.provideField(getAbsoluteFieldNumber());
    if (containerIsStoredInSingleColumn()) {
        if (value != null) {
            if (mmd.getCollection().elementIsPersistent()) {
                // Make sure all persistable elements have ObjectProviders
                Object[] collElements = value.toArray();
                for (Object elem : collElements) {
                    if (elem != null) {
                        ObjectProvider elemOP = ec.findObjectProvider(elem);
                        if (elemOP == null || ec.getApiAdapter().getExecutionContext(elem) == null) {
                            elemOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, elem, false, ownerOP, mmd.getAbsoluteFieldNumber());
                        }
                    }
                }
            }
        }
        return;
    }
    if (value == null) {
        // replace null collections with an empty SCO wrapper
        replaceFieldWithWrapper(ownerOP, 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", 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 (ownerOP.getExecutionContext().getApiAdapter().isDetached(collElement)) {
            needsAttaching = true;
            break;
        }
    }
    if (needsAttaching) {
        // Create a wrapper and attach the elements (and add the others)
        SCO collWrapper = replaceFieldWithWrapper(ownerOP, null);
        if (value.size() > 0) {
            collWrapper.attachCopy(value);
            // The attach will have put entries in the operationQueue if using optimistic, so flush them
            ownerOP.getExecutionContext().flushOperationsForBackingStore(((BackedSCO) collWrapper).getBackingStore(), ownerOP);
        }
    } else {
        if (value.size() > 0) {
            // Add the elements direct to the datastore
            ((CollectionStore) storeMgr.getBackingStoreForField(ownerOP.getExecutionContext().getClassLoaderResolver(), mmd, value.getClass())).addAll(ownerOP, value, 0);
            // Create a SCO wrapper with the elements loaded
            replaceFieldWithWrapper(ownerOP, value);
        } else {
            if (mmd.getRelationType(ownerOP.getExecutionContext().getClassLoaderResolver()) == RelationType.MANY_TO_MANY_BI) {
                // Create a SCO wrapper, pass in null so it loads any from the datastore (on other side?)
                replaceFieldWithWrapper(ownerOP, null);
            } else {
                // Create a SCO wrapper, pass in empty collection to avoid loading from DB (extra SQL)
                replaceFieldWithWrapper(ownerOP, value);
            }
        }
    }
}
Also used : ExecutionContext(org.datanucleus.ExecutionContext) Collection(java.util.Collection) ObjectProvider(org.datanucleus.state.ObjectProvider) 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 7 with SCO

use of org.datanucleus.store.types.SCO in project datanucleus-rdbms by datanucleus.

the class ArrayMapping method postInsert.

/**
 * Method to be called after the insert of the owner class element.
 * @param ownerOP ObjectProvider of the owner
 */
public void postInsert(ObjectProvider ownerOP) {
    ExecutionContext ec = ownerOP.getExecutionContext();
    Object value = ownerOP.provideField(getAbsoluteFieldNumber());
    if (value == null) {
        return;
    }
    if (containerIsStoredInSingleColumn()) {
        if (mmd.getArray().elementIsPersistent()) {
            // Make sure all persistable elements have ObjectProviders
            Object[] arrElements = (Object[]) value;
            for (Object elem : arrElements) {
                if (elem != null) {
                    ObjectProvider elemOP = ec.findObjectProvider(elem);
                    if (elemOP == null || ec.getApiAdapter().getExecutionContext(elem) == null) {
                        elemOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, elem, false, ownerOP, mmd.getAbsoluteFieldNumber());
                    }
                }
            }
        }
        return;
    }
    int arrayLength = Array.getLength(value);
    boolean persistentElements = (mmd.getRelationType(ec.getClassLoaderResolver()) != RelationType.NONE);
    boolean needsAttaching = false;
    if (persistentElements) {
        Object[] array = (Object[]) value;
        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 (int i = 0; i < arrayLength; i++) {
                if (!ec.getApiAdapter().isDetached(array[i]) && !ec.getApiAdapter().isPersistent(array[i])) {
                    // Element is not persistent so throw exception
                    throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), array[i]);
                }
            }
        } else {
            // Reachability
            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", mmd.getFullFieldName()));
            }
        }
        for (int i = 0; i < arrayLength; i++) {
            if (ownerOP.getExecutionContext().getApiAdapter().isDetached(array[i])) {
                needsAttaching = true;
                break;
            }
        }
    }
    if (needsAttaching) {
        // Create a wrapper and attach the elements (and add the others)
        SCO collWrapper = replaceFieldWithWrapper(ownerOP, null);
        if (arrayLength > 0) {
            collWrapper.attachCopy(value);
            // The attach will have put entries in the operationQueue if using optimistic, so flush them
            ownerOP.getExecutionContext().flushOperationsForBackingStore(((BackedSCO) collWrapper).getBackingStore(), ownerOP);
        }
    } else {
        if (arrayLength > 0) {
            // Add the elements direct to the datastore
            ((ArrayStore) storeMgr.getBackingStoreForField(ownerOP.getExecutionContext().getClassLoaderResolver(), mmd, null)).set(ownerOP, value);
        }
    }
}
Also used : ExecutionContext(org.datanucleus.ExecutionContext) ObjectProvider(org.datanucleus.state.ObjectProvider) ArrayStore(org.datanucleus.store.types.scostore.ArrayStore) SCO(org.datanucleus.store.types.SCO) BackedSCO(org.datanucleus.store.types.wrappers.backed.BackedSCO) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException)

Example 8 with SCO

use of org.datanucleus.store.types.SCO in project datanucleus-rdbms by datanucleus.

the class MapMapping method preDelete.

/**
 * Method to be called before any delete of the owner class element.
 * @param ownerOP ObjectProvider of the owner
 */
public void preDelete(ObjectProvider ownerOP) {
    // Do nothing - dependent deletion is performed by deleteDependent()
    if (containerIsStoredInSingleColumn()) {
        // Do nothing when serialised since we are handled in the main request
        return;
    }
    // makes sure field is loaded
    ownerOP.isLoaded(getAbsoluteFieldNumber());
    java.util.Map value = (java.util.Map) ownerOP.provideField(getAbsoluteFieldNumber());
    if (value == null) {
        // Do nothing
        return;
    }
    if (!(value instanceof SCO)) {
        // Make sure we have a SCO wrapper so we can clear from the datastore
        value = (java.util.Map) SCOUtils.wrapSCOField(ownerOP, mmd.getAbsoluteFieldNumber(), value, true);
    }
    value.clear();
    // Flush any outstanding updates for this backing store
    ownerOP.getExecutionContext().flushOperationsForBackingStore(((BackedSCO) value).getBackingStore(), ownerOP);
}
Also used : Map(java.util.Map) Map(java.util.Map) SCO(org.datanucleus.store.types.SCO) BackedSCO(org.datanucleus.store.types.wrappers.backed.BackedSCO)

Example 9 with SCO

use of org.datanucleus.store.types.SCO in project datanucleus-core by datanucleus.

the class L2CachePopulateFieldManager method processField.

private void processField(int fieldNumber, Object value, AbstractMemberMetaData mmd) {
    RelationType relType = mmd.getRelationType(ec.getClassLoaderResolver());
    if (relType == RelationType.NONE) {
        Object unwrappedValue = value instanceof SCO ? ((SCO) value).getValue() : value;
        cachedPC.setFieldValue(fieldNumber, SCOUtils.copyValue(unwrappedValue));
        return;
    }
    // 1-1, N-1 persistable field
    if (mmd.isSerialized() || MetaDataUtils.isMemberEmbedded(mmd, relType, ec.getClassLoaderResolver(), ec.getMetaDataManager())) {
        if (ec.getNucleusContext().getConfiguration().getBooleanProperty(PropertyNames.PROPERTY_CACHE_L2_CACHE_EMBEDDED)) {
            // Put object in cached as (nested) CachedPC
            cachedPC.setFieldValue(fieldNumber, convertPersistableToCachedPC(value));
        } else {
            // User not caching embedded/serialised
            cachedPC.setLoadedField(fieldNumber, false);
        }
    } else {
        // Put cacheable form of the id in CachedPC
        cachedPC.setFieldValue(fieldNumber, getCacheableIdForId(ec.getApiAdapter(), value));
    }
}
Also used : RelationType(org.datanucleus.metadata.RelationType) SCO(org.datanucleus.store.types.SCO)

Example 10 with SCO

use of org.datanucleus.store.types.SCO in project datanucleus-core by datanucleus.

the class AttachFieldManager method storeObjectField.

/**
 * Method to store an object field into the attached instance.
 * @param fieldNumber Number of the field to store
 * @param value the value in the detached instance
 */
public void storeObjectField(int fieldNumber, Object value) {
    // Note : when doing updates always do replaceField first and makeDirty after since the replaceField
    // can cause flush() to be called meaning that an update with null would be made before the new value
    // makes it into the field
    AbstractClassMetaData cmd = attachedOP.getClassMetaData();
    AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
    ExecutionContext ec = attachedOP.getExecutionContext();
    RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
    // boolean processWhenExisting = true;
    if (mmd.hasExtension("attach")) {
        if (mmd.getValueForExtension("attach").equalsIgnoreCase("never")) {
            // Member is tagged to not attach, so put a null
            attachedOP.replaceFieldMakeDirty(fieldNumber, null);
            return;
        }
    // TODO Support attach only when not present in the datastore (only for PCs)
    // else if (mmd.getValueForExtension("attach").equalsIgnoreCase("when-non-existing"))
    // {
    // processWhenExisting = false;
    // }
    }
    // Use ContainerHandlers to support non-JDK Collections and single element collections
    ApiAdapter api = ec.getApiAdapter();
    if (value == null) {
        Object oldValue = null;
        if (mmd.isDependent() && persistent) {
            // Get any old value of this field so we can do cascade-delete if being nulled
            try {
                attachedOP.loadFieldFromDatastore(fieldNumber);
            } catch (Exception e) {
            // Error loading the field so didn't exist before attaching anyway
            }
            oldValue = attachedOP.provideField(fieldNumber);
        }
        attachedOP.replaceField(fieldNumber, null);
        if (dirtyFields[fieldNumber] || !persistent) {
            attachedOP.makeDirty(fieldNumber);
        }
        if (mmd.isDependent() && !mmd.isEmbedded() && oldValue != null && api.isPersistable(oldValue)) {
            // Check for a field storing a PC where it is being nulled and the other object is dependent
            // Flush the nulling of the field
            attachedOP.flush();
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("026026", oldValue, mmd.getFullFieldName()));
            ec.deleteObjectInternal(oldValue);
        }
    } else if (secondClassMutableFields[fieldNumber]) {
        if (mmd.isSerialized() && !RelationType.isRelationMultiValued(relationType)) {
            // SCO Field is serialised, and no persistable elements so just update the column with this new value
            attachedOP.replaceFieldMakeDirty(fieldNumber, value);
            attachedOP.makeDirty(fieldNumber);
        } else {
            // Make sure that the value is a SCO wrapper
            Object oldValue = null;
            if (persistent && !attachedOP.isFieldLoaded(fieldNumber)) {
                attachedOP.loadField(fieldNumber);
            }
            oldValue = attachedOP.provideField(fieldNumber);
            boolean changed = dirtyFields[fieldNumber];
            if (!changed) {
                // Check if the new value is different (not detected if detached field was not a wrapper and mutable)
                if (oldValue == null) {
                    changed = true;
                } else {
                    if (mmd.hasCollection() && relationType != RelationType.NONE) {
                        boolean collsEqual = SCOUtils.collectionsAreEqual(api, (Collection) oldValue, (Collection) value);
                        changed = !collsEqual;
                    } else // TODO Do like the above for relational Maps
                    {
                        changed = !(oldValue.equals(value));
                    }
                }
            }
            SCO sco;
            if (oldValue == null || !(oldValue instanceof SCO)) {
                // Detached object didn't use wrapped field
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("026029", StringUtils.toJVMIDString(attachedOP.getObject()), attachedOP.getInternalObjectId(), mmd.getName()));
                }
                sco = ec.getTypeManager().createSCOInstance(attachedOP, mmd, value != null ? value.getClass() : null, null, false);
                if (sco instanceof SCOContainer) {
                    // Load any containers to avoid update issues
                    ((SCOContainer) sco).load();
                }
                attachedOP.replaceFieldMakeDirty(fieldNumber, sco);
            } else {
                // The field is already a SCO wrapper, so just copy the new values to it
                sco = (SCO) oldValue;
            }
            if (cascadeAttach) {
                // Only trigger the cascade when required
                if (copy) {
                    // Attach copy of the SCO
                    sco.attachCopy(value);
                } else {
                    // Should be changed to do things like in attachCopy above.
                    if (sco instanceof Collection) {
                        // Attach all PC elements of the collection
                        SCOUtils.attachForCollection(attachedOP, ((Collection) value).toArray(), SCOUtils.collectionHasElementsWithoutIdentity(mmd));
                    } else if (sco instanceof Map) {
                        // Attach all PC keys/values of the map
                        SCOUtils.attachForMap(attachedOP, ((Map) value).entrySet(), SCOUtils.mapHasKeysWithoutIdentity(mmd), SCOUtils.mapHasValuesWithoutIdentity(mmd));
                    } else {
                        // Initialise the SCO with the new value
                        sco.initialise(value);
                    }
                }
            }
            if (changed || !persistent) {
                attachedOP.makeDirty(fieldNumber);
            }
        }
    } else if (mmd.getType().isArray() && RelationType.isRelationMultiValued(relationType)) {
        // Array of persistable objects
        if (mmd.isSerialized() || mmd.isEmbedded()) {
            // Field is serialised/embedded so just update the column with this new value TODO Make sure they have ObjectProviders
            attachedOP.replaceField(fieldNumber, value);
            if (dirtyFields[fieldNumber] || !persistent) {
                attachedOP.makeDirty(fieldNumber);
            }
        } else {
            Object oldValue = attachedOP.provideField(fieldNumber);
            if (oldValue == null && !attachedOP.getLoadedFields()[fieldNumber] && persistent) {
                // Retrieve old value for field
                attachedOP.loadField(fieldNumber);
                oldValue = attachedOP.provideField(fieldNumber);
            }
            if (cascadeAttach) {
                // Only trigger the cascade when required
                Object arr = Array.newInstance(mmd.getType().getComponentType(), Array.getLength(value));
                for (int i = 0; i < Array.getLength(value); i++) {
                    Object elem = Array.get(value, i);
                    // TODO Compare with old value and handle delete dependent etc
                    if (copy) {
                        Object elemAttached = ec.attachObjectCopy(attachedOP, elem, false);
                        Array.set(arr, i, elemAttached);
                    } else {
                        ec.attachObject(attachedOP, elem, false);
                        Array.set(arr, i, elem);
                    }
                }
                attachedOP.replaceFieldMakeDirty(fieldNumber, arr);
            }
            if (dirtyFields[fieldNumber] || !persistent) {
                attachedOP.makeDirty(fieldNumber);
            }
        }
    } else if (RelationType.isRelationSingleValued(relationType)) {
        // 1-1/N-1
        ObjectProvider valueSM = ec.findObjectProvider(value);
        if (valueSM != null && valueSM.getReferencedPC() != null && !api.isPersistent(value)) {
            // Value has ObjectProvider and has referenced object so is being attached, so refer to attached PC
            if (dirtyFields[fieldNumber]) {
                attachedOP.replaceFieldMakeDirty(fieldNumber, valueSM.getReferencedPC());
            } else {
                attachedOP.replaceField(fieldNumber, valueSM.getReferencedPC());
            }
        }
        if (cascadeAttach) {
            // Determine if field is persisted into the owning object (embedded/serialised)
            boolean sco = mmd.getEmbeddedMetaData() != null || mmd.isSerialized() || mmd.isEmbedded();
            if (copy) {
                // Attach copy of the PC
                value = ec.attachObjectCopy(attachedOP, value, sco);
                if (sco || dirtyFields[fieldNumber]) {
                    // Either embedded/serialised or marked as changed, so make it dirty
                    attachedOP.replaceFieldMakeDirty(fieldNumber, value);
                } else {
                    attachedOP.replaceField(fieldNumber, value);
                }
            } else {
                // Attach PC in-situ
                ec.attachObject(attachedOP, value, sco);
            }
            // Make sure the field is marked as dirty
            if (dirtyFields[fieldNumber] || !persistent) {
                attachedOP.makeDirty(fieldNumber);
            } else if (sco && value != null && api.isDirty(value)) {
                attachedOP.makeDirty(fieldNumber);
            }
        } else if (dirtyFields[fieldNumber] || !persistent) {
            attachedOP.makeDirty(fieldNumber);
        }
    } else {
        attachedOP.replaceField(fieldNumber, value);
        if (dirtyFields[fieldNumber] || !persistent) {
            attachedOP.makeDirty(fieldNumber);
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SCOContainer(org.datanucleus.store.types.SCOContainer) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) Collection(java.util.Collection) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) Map(java.util.Map) SCO(org.datanucleus.store.types.SCO)

Aggregations

SCO (org.datanucleus.store.types.SCO)12 ExecutionContext (org.datanucleus.ExecutionContext)5 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)5 Collection (java.util.Collection)4 RelationType (org.datanucleus.metadata.RelationType)4 ObjectProvider (org.datanucleus.state.ObjectProvider)4 BackedSCO (org.datanucleus.store.types.wrappers.backed.BackedSCO)4 ApiAdapter (org.datanucleus.api.ApiAdapter)3 TypeManager (org.datanucleus.store.types.TypeManager)3 Map (java.util.Map)2 ReachableObjectNotCascadedException (org.datanucleus.exceptions.ReachableObjectNotCascadedException)2 ContainerHandler (org.datanucleus.store.types.ContainerHandler)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)1 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)1 ContainerAdapter (org.datanucleus.store.types.ContainerAdapter)1 SCOContainer (org.datanucleus.store.types.SCOContainer)1 ArrayStore (org.datanucleus.store.types.scostore.ArrayStore)1 CollectionStore (org.datanucleus.store.types.scostore.CollectionStore)1