use of org.datanucleus.ExecutionContext in project datanucleus-rdbms by datanucleus.
the class FKMapStore method remove.
/**
* Method to remove an entry from the map.
* @param op ObjectProvider for the map.
* @param key Key of the entry to remove.
* @return The value that was removed.
*/
public V remove(ObjectProvider op, Object key, Object oldValue) {
ExecutionContext ec = op.getExecutionContext();
if (keyFieldNumber >= 0) {
// Key stored in value
if (oldValue != null) {
boolean deletingValue = false;
ObjectProvider valueOP = ec.findObjectProvider(oldValue);
if (ownerMemberMetaData.getMap().isDependentValue()) {
// Delete the value if it is dependent
deletingValue = true;
ec.deleteObjectInternal(oldValue);
valueOP.flush();
} else if (ownerMapping.isNullable()) {
// Null the owner FK
if (ownerFieldNumber >= 0) {
// Update the field in the value
Object oldOwner = valueOP.provideField(ownerFieldNumber);
valueOP.replaceFieldMakeDirty(ownerFieldNumber, null);
valueOP.flush();
if (ec.getManageRelations()) {
ec.getRelationshipManager(valueOP).relationChange(ownerFieldNumber, oldOwner, null);
}
} else {
// Update the external FK in the value in the datastore
updateValueFkInternal(op, oldValue, null);
}
} else {
// Not nullable, so must delete since no other way of removing from map
deletingValue = true;
ec.deleteObjectInternal(oldValue);
valueOP.flush();
}
if (ownerMemberMetaData.getMap().isDependentKey()) {
// Delete the key since it is dependent
if (!deletingValue) {
// Null FK in value to key
if (keyMapping.isNullable()) {
valueOP.replaceFieldMakeDirty(keyFieldNumber, null);
valueOP.flush();
if (ec.getManageRelations()) {
ec.getRelationshipManager(valueOP).relationChange(keyFieldNumber, key, null);
}
}
}
ec.deleteObjectInternal(key);
ObjectProvider keyOP = ec.findObjectProvider(key);
keyOP.flush();
}
}
} else {
// Value stored in key
if (key != null) {
boolean deletingKey = false;
ObjectProvider keyOP = ec.findObjectProvider(key);
if (ownerMemberMetaData.getMap().isDependentKey()) {
// Delete the key if it is dependent
deletingKey = true;
ec.deleteObjectInternal(key);
keyOP.flush();
} else if (ownerMapping.isNullable()) {
// Null the owner FK
if (ownerFieldNumber >= 0) {
// Update the field in the key
Object oldOwner = keyOP.provideField(ownerFieldNumber);
keyOP.replaceFieldMakeDirty(ownerFieldNumber, null);
keyOP.flush();
if (ec.getManageRelations()) {
ec.getRelationshipManager(keyOP).relationChange(ownerFieldNumber, oldOwner, null);
}
} else {
// Update the external FK in the key in the datastore
updateKeyFkInternal(op, key, null);
}
} else {
// Not nullable, so must delete since no other way of removing from map
deletingKey = true;
ec.deleteObjectInternal(key);
keyOP.flush();
}
if (ownerMemberMetaData.getMap().isDependentValue()) {
// Delete the value since it is dependent
if (!deletingKey) {
// Null FK in key to value
if (valueMapping.isNullable()) {
keyOP.replaceFieldMakeDirty(valueFieldNumber, null);
keyOP.flush();
if (ec.getManageRelations()) {
ec.getRelationshipManager(keyOP).relationChange(valueFieldNumber, oldValue, null);
}
}
}
ec.deleteObjectInternal(oldValue);
ObjectProvider valOP = ec.findObjectProvider(oldValue);
valOP.flush();
}
}
}
return (V) oldValue;
}
use of org.datanucleus.ExecutionContext in project datanucleus-rdbms by datanucleus.
the class FKMapStore method removeValue.
/**
* Utility to remove a value from the Map.
* @param op ObjectProvider for the map.
* @param key Key of the object
* @param oldValue Value to remove
*/
private void removeValue(ObjectProvider op, Object key, Object oldValue) {
ExecutionContext ec = op.getExecutionContext();
// Null out the key and owner fields if they are nullable
if (keyMapping.isNullable()) {
ObjectProvider vsm = ec.findObjectProvider(oldValue);
// Null the key field
vsm.replaceFieldMakeDirty(keyFieldNumber, null);
if (ec.getManageRelations()) {
ec.getRelationshipManager(vsm).relationChange(keyFieldNumber, key, null);
}
// Null the owner field
if (ownerFieldNumber >= 0) {
Object oldOwner = vsm.provideField(ownerFieldNumber);
vsm.replaceFieldMakeDirty(ownerFieldNumber, null);
if (ec.getManageRelations()) {
ec.getRelationshipManager(vsm).relationChange(ownerFieldNumber, oldOwner, null);
}
} else {
updateValueFk(op, oldValue, null);
}
} else // otherwise just delete the item
{
ec.deleteObjectInternal(oldValue);
}
}
use of org.datanucleus.ExecutionContext in project datanucleus-rdbms by datanucleus.
the class FKMapStore method put.
/**
* Method to put an item in the Map.
* @param op ObjectProvider for the map.
* @param newKey The key to store the value against
* @param newValue The value to store.
* @return The value stored.
*/
public V put(final ObjectProvider op, final K newKey, V newValue) {
ExecutionContext ec = op.getExecutionContext();
if (keyFieldNumber >= 0) {
validateKeyForWriting(op, newKey);
validateValueType(ec.getClassLoaderResolver(), newValue);
} else {
validateKeyType(ec.getClassLoaderResolver(), newKey);
validateValueForWriting(op, newValue);
}
// Check if there is an existing value for this key
V oldValue = get(op, newKey);
if (oldValue != newValue) {
if (valueCmd != null) {
if (oldValue != null && !oldValue.equals(newValue)) {
// Key is stored in the value and the value has changed so remove the old value
removeValue(op, newKey, oldValue);
}
final Object newOwner = op.getObject();
if (ec.getApiAdapter().isPersistent(newValue)) {
/*
* The new value is already persistent.
*
* "Put" the new value in the map by updating its owner and key
* fields to the appropriate values. This is done with the same
* methods the PC itself would use if the application code
* modified the fields. It should result in no actual database
* activity if the fields were already set to the right values.
*/
if (ec != ec.getApiAdapter().getExecutionContext(newValue)) {
throw new NucleusUserException(Localiser.msg("RDBMS.SCO.Map.WriteValueInvalidWithDifferentPM"), ec.getApiAdapter().getIdForObject(newValue));
}
ObjectProvider vsm = ec.findObjectProvider(newValue);
// Ensure the current owner field is loaded, and replace with new value
if (ownerFieldNumber >= 0) {
vsm.isLoaded(ownerFieldNumber);
Object oldOwner = vsm.provideField(ownerFieldNumber);
vsm.replaceFieldMakeDirty(ownerFieldNumber, newOwner);
if (ec.getManageRelations()) {
ec.getRelationshipManager(vsm).relationChange(ownerFieldNumber, oldOwner, newOwner);
}
} else {
updateValueFk(op, newValue, newOwner);
}
// Ensure the current key field is loaded, and replace with new value
vsm.isLoaded(keyFieldNumber);
Object oldKey = vsm.provideField(keyFieldNumber);
vsm.replaceFieldMakeDirty(keyFieldNumber, newKey);
if (ec.getManageRelations()) {
ec.getRelationshipManager(vsm).relationChange(keyFieldNumber, oldKey, newKey);
}
} else {
/*
* The new value is not yet persistent.
*
* Update its owner and key fields to the appropriate values and
* *then* make it persistent. Making the changes before DB
* insertion avoids an unnecessary UPDATE allows the owner
* and/or key fields to be non-nullable.
*/
ec.persistObjectInternal(newValue, new FieldValues() {
public void fetchFields(ObjectProvider vsm) {
if (ownerFieldNumber >= 0) {
vsm.replaceFieldMakeDirty(ownerFieldNumber, newOwner);
}
vsm.replaceFieldMakeDirty(keyFieldNumber, newKey);
JavaTypeMapping externalFKMapping = valueTable.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
if (externalFKMapping != null) {
// Set the owner in the value object where appropriate
vsm.setAssociatedValue(externalFKMapping, op.getObject());
}
}
public void fetchNonLoadedFields(ObjectProvider op) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, ObjectProvider.PC);
}
} else {
// Value is stored in the key
final Object newOwner = op.getObject();
if (ec.getApiAdapter().isPersistent(newKey)) {
/*
* The new key is already persistent.
*
* "Put" the new key in the map by updating its owner and value
* fields to the appropriate values. This is done with the same
* methods the PC itself would use if the application code
* modified the fields. It should result in no actual database
* activity if the fields were already set to the right values.
*/
if (ec != ec.getApiAdapter().getExecutionContext(newKey)) {
throw new NucleusUserException(Localiser.msg("056060"), ec.getApiAdapter().getIdForObject(newKey));
}
ObjectProvider valOP = ec.findObjectProvider(newKey);
// Ensure the current owner field is loaded, and replace with new key
if (ownerFieldNumber >= 0) {
valOP.isLoaded(ownerFieldNumber);
Object oldOwner = valOP.provideField(ownerFieldNumber);
valOP.replaceFieldMakeDirty(ownerFieldNumber, newOwner);
if (ec.getManageRelations()) {
ec.getRelationshipManager(valOP).relationChange(ownerFieldNumber, oldOwner, newOwner);
}
} else {
updateKeyFk(op, newKey, newOwner);
}
// Ensure the current value field is loaded, and replace with new value
valOP.isLoaded(valueFieldNumber);
// TODO Should we update the local variable ?
oldValue = (V) valOP.provideField(valueFieldNumber);
valOP.replaceFieldMakeDirty(valueFieldNumber, newValue);
if (ec.getManageRelations()) {
ec.getRelationshipManager(valOP).relationChange(valueFieldNumber, oldValue, newValue);
}
} else {
/*
* The new key is not yet persistent.
*
* Update its owner and key fields to the appropriate values and
* *then* make it persistent. Making the changes before DB
* insertion avoids an unnecessary UPDATE allows the owner
* and/or key fields to be non-nullable.
*/
final Object newValueObj = newValue;
ec.persistObjectInternal(newKey, new FieldValues() {
public void fetchFields(ObjectProvider vsm) {
if (ownerFieldNumber >= 0) {
vsm.replaceFieldMakeDirty(ownerFieldNumber, newOwner);
}
vsm.replaceFieldMakeDirty(valueFieldNumber, newValueObj);
JavaTypeMapping externalFKMapping = valueTable.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
if (externalFKMapping != null) {
// Set the owner in the value object where appropriate
vsm.setAssociatedValue(externalFKMapping, op.getObject());
}
}
public void fetchNonLoadedFields(ObjectProvider op) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, ObjectProvider.PC);
/*if (ownerFieldNumber < 0)
{
// TODO Think about removing this since we set the associated owner here
updateKeyFk(sm, newKey, newOwner);
}*/
}
}
}
// TODO Cater for key being PC and having delete-dependent
if (ownerMemberMetaData.getMap().isDependentValue() && oldValue != null) {
// Delete the old value if it is no longer contained and is dependent
if (!containsValue(op, oldValue)) {
ec.deleteObjectInternal(oldValue);
}
}
return oldValue;
}
use of org.datanucleus.ExecutionContext in project datanucleus-rdbms by datanucleus.
the class FKSetStore method updateElementFk.
/**
* Utility to update a foreign-key (and distinguisher) in the element in the case of a unidirectional 1-N relationship.
* @param ownerOP ObjectProvider for the owner
* @param element The element to update
* @param owner The owner object to set in the FK
* @return Whether it was performed successfully
*/
private boolean updateElementFk(ObjectProvider ownerOP, Object element, Object owner) {
if (element == null) {
return false;
}
validateElementForWriting(ownerOP.getExecutionContext(), element, null);
boolean retval;
ExecutionContext ec = ownerOP.getExecutionContext();
String stmt = getUpdateFkStmt(element);
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, stmt, false);
try {
ComponentInfo elemInfo = getComponentInfoForElement(element);
JavaTypeMapping ownerMapping = elemInfo.getOwnerMapping();
JavaTypeMapping elemMapping = elemInfo.getDatastoreClass().getIdMapping();
int jdbcPosition = 1;
if (owner == null) {
ownerMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, ownerMapping), null, ownerOP, ownerMemberMetaData.getAbsoluteFieldNumber());
} else {
ownerMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, ownerMapping), ownerOP.getObject(), ownerOP, ownerMemberMetaData.getAbsoluteFieldNumber());
}
jdbcPosition += ownerMapping.getNumberOfDatastoreMappings();
if (relationDiscriminatorMapping != null) {
jdbcPosition = BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, this);
}
jdbcPosition = BackingStoreHelper.populateElementForWhereClauseInStatement(ec, ps, element, jdbcPosition, elemMapping);
sqlControl.executeStatementUpdate(ec, mconn, stmt, ps, true);
retval = true;
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException e) {
throw new NucleusDataStoreException(Localiser.msg("056027", stmt), e);
}
return retval;
}
use of org.datanucleus.ExecutionContext in project datanucleus-rdbms by datanucleus.
the class FKSetStore method add.
/**
* Method to add an object to the relationship at the collection end.
* @param ownerOP ObjectProvider for the owner.
* @param element Element to be added
* @return Success indicator
*/
public boolean add(final ObjectProvider ownerOP, E element, int size) {
if (element == null) {
// Sets allow no duplicates
throw new NucleusUserException(Localiser.msg("056039"));
}
// Make sure that the element is persisted in the datastore (reachability)
final Object newOwner = ownerOP.getObject();
final ExecutionContext ec = ownerOP.getExecutionContext();
// Find the (element) table storing the FK back to the owner
boolean isPersistentInterface = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType);
DatastoreClass elementTable = null;
if (isPersistentInterface) {
elementTable = storeMgr.getDatastoreClass(storeMgr.getNucleusContext().getMetaDataManager().getImplementationNameForPersistentInterface(elementType), clr);
} else {
Class elementTypeCls = clr.classForName(elementType);
if (elementTypeCls.isInterface()) {
// Set<interface> so use type of element passed in and get its table
elementTable = storeMgr.getDatastoreClass(element.getClass().getName(), clr);
} else {
// Use table for element type
elementTable = storeMgr.getDatastoreClass(elementType, clr);
}
}
if (elementTable == null) {
// "subclass-table", persisted into table of other class
AbstractClassMetaData[] managingCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
if (managingCmds != null && managingCmds.length > 0) {
// Find which of these subclasses is appropriate for this element
for (int i = 0; i < managingCmds.length; i++) {
Class tblCls = clr.classForName(managingCmds[i].getFullClassName());
if (tblCls.isAssignableFrom(element.getClass())) {
elementTable = storeMgr.getDatastoreClass(managingCmds[i].getFullClassName(), clr);
break;
}
}
}
}
final DatastoreClass elementTbl = elementTable;
boolean inserted = validateElementForWriting(ec, element, new FieldValues() {
public void fetchFields(ObjectProvider elementOP) {
if (elementTbl != null) {
JavaTypeMapping externalFKMapping = elementTbl.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
if (externalFKMapping != null) {
// The element has an external FK mapping so set the value it needs to use in the INSERT
elementOP.setAssociatedValue(externalFKMapping, ownerOP.getObject());
}
if (relationDiscriminatorMapping != null) {
// Element type has a shared FK so set the discriminator value for this relation
elementOP.setAssociatedValue(relationDiscriminatorMapping, relationDiscriminatorValue);
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0) {
// TODO Move this into RelationshipManager
// Managed Relations : 1-N bidir, so make sure owner is correct at persist
Object currentOwner = elementOP.provideField(fieldNumInElement);
if (currentOwner == null) {
// No owner, so correct it
NucleusLogger.PERSISTENCE.info(Localiser.msg("056037", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject())));
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
} else if (currentOwner != newOwner) {
// Check for owner change
Object ownerId1 = ec.getApiAdapter().getIdForObject(currentOwner);
Object ownerId2 = ec.getApiAdapter().getIdForObject(newOwner);
if (ownerId1 != null && ownerId2 != null && ownerId1.equals(ownerId2)) {
// Must be attaching
if (!ec.getApiAdapter().isDetached(newOwner)) {
// Attaching, so make sure we set to the attached owner
elementOP.replaceField(fieldNumInElement, newOwner);
}
} else if (ownerOP.getReferencedPC() == null) {
// Not being attached so must be inconsistent owner, so throw exception
throw new NucleusUserException(Localiser.msg("056038", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject()), StringUtils.toJVMIDString(currentOwner)));
}
}
}
}
public void fetchNonLoadedFields(ObjectProvider op) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
});
if (inserted) {
// Element has just been persisted so the FK will be set
return true;
}
// Element was already persistent so make sure the FK is in place
// TODO This is really "ManagedRelationships" so needs to go in RelationshipManager
ObjectProvider elementOP = ec.findObjectProvider(element);
if (elementOP == null) {
// Element is likely being attached and this is the detached element; lookup the attached element via the id
Object elementId = ec.getApiAdapter().getIdForObject(element);
if (elementId != null) {
element = (E) ec.findObject(elementId, false, false, element.getClass().getName());
if (element != null) {
elementOP = ec.findObjectProvider(element);
}
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0 && elementOP != null) {
// Managed Relations : 1-N bidir, so update the owner of the element
// Ensure is loaded
elementOP.isLoaded(fieldNumInElement);
Object oldOwner = elementOP.provideField(fieldNumInElement);
if (oldOwner != newOwner) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055009", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
if (ec.getManageRelations()) {
// Managed Relationships - add the change we've made here to be analysed at flush
RelationshipManager relationshipManager = ec.getRelationshipManager(elementOP);
relationshipManager.relationChange(fieldNumInElement, oldOwner, newOwner);
if (ec.isFlushing()) {
// When already flushing process the changes right away to make them effective during the current flush
relationshipManager.process();
}
}
if (ec.isFlushing()) {
elementOP.flush();
}
}
return oldOwner != newOwner;
}
// 1-N unidir so update the FK if not set to be contained in the set
boolean contained = contains(ownerOP, element);
return (contained ? false : updateElementFk(ownerOP, element, newOwner));
}
Aggregations