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);
}
}
}
}
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);
}
}
}
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);
}
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));
}
}
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);
}
}
}
Aggregations