/** * INTERNAL: * Update the privately owned parts */ public void postUpdate(WriteObjectQuery writeQuery) throws DatabaseException, OptimisticLockException { if (isReadOnly()) { return; } // If objects are not instantiated that means they are not changed. if (!isAttributeValueInstantiatedOrChanged(writeQuery.getObject())) { return; } // Manage objects added and removed from the collection. Object objects = getRealCollectionAttributeValueFromObject(writeQuery.getObject(), writeQuery.getSession()); Object currentObjectsInDB = readPrivateOwnedForObject(writeQuery); if (currentObjectsInDB == null) { currentObjectsInDB = getContainerPolicy().containerInstance(1); } compareObjectsAndWrite(currentObjectsInDB, objects, writeQuery); }
/** * INTERNAL: * The foreign keys and the primary key names are converted to DatabaseFields and stored. */ protected void initializeTargetForeignKeyToSourceKeys(AbstractSession session) throws DescriptorException { if (getTargetForeignKeyFields().isEmpty()) { throw DescriptorException.noTargetForeignKeysSpecified(this); } for (int index = 0; index < getTargetForeignKeyFields().size(); index++) { DatabaseField foreignKeyfield = getTargetForeignKeyFields().get(index); foreignKeyfield = getReferenceDescriptor().buildField(foreignKeyfield); getTargetForeignKeyFields().set(index, foreignKeyfield); } for (int index = 0; index < getSourceKeyFields().size(); index++) { DatabaseField sourceKeyfield = getSourceKeyFields().get(index); sourceKeyfield = getDescriptor().buildField(sourceKeyfield); getSourceKeyFields().set(index, sourceKeyfield); } if (getTargetForeignKeyFields().size() != getSourceKeyFields().size()) { throw DescriptorException.targetForeignKeysSizeMismatch(this); } Iterator<DatabaseField> targetForeignKeysEnum = getTargetForeignKeyFields().iterator(); Iterator<DatabaseField> sourceKeysEnum = getSourceKeyFields().iterator(); while (targetForeignKeysEnum.hasNext()) { getTargetForeignKeyToSourceKeys().put(targetForeignKeysEnum.next(), sourceKeysEnum.next()); } }
/** * INTERNAL: * Old and new lists are compared and only the changes are written to the database. * Called only if listOrderField != null */ protected void compareListsAndWrite(List previousList, List currentList, WriteObjectQuery query) throws DatabaseException, OptimisticLockException { if(this.isListOrderFieldUpdatable) { compareListsAndWrite_UpdatableListOrderField(previousList, currentList, query); } else { compareListsAndWrite_NonUpdatableListOrderField(previousList, currentList, query); } }
/** * PUBLIC: * Define the target foreign key relationship in the 1-M aggregate collection mapping. * Both the target foreign key field and the source primary key field must be specified. */ public void addTargetForeignKeyField(DatabaseField targetForeignKey, DatabaseField sourceKey) { getTargetForeignKeyFields().addElement(targetForeignKey); getSourceKeyFields().addElement(sourceKey); }
public void setAttributeValueInObject(Object object, Object value) { AggregateCollectionMapping mapping = (AggregateCollectionMapping)object; List associations = (List)value; mapping.setSourceKeyFields(NonSynchronizedVector.newInstance(associations.size())); mapping.setTargetForeignKeyFields(NonSynchronizedVector.newInstance(associations.size())); Iterator iterator = associations.iterator(); while (iterator.hasNext()) { Association association = (Association)iterator.next(); mapping.getSourceKeyFields().add((DatabaseField)association.getValue()); mapping.getTargetForeignKeyFields().add((DatabaseField)association.getKey()); } } });
/** * INTERNAL: * Cascade perform removal of orphaned private owned objects from the UnitOfWorkChangeSet */ @Override public void cascadePerformRemovePrivateOwnedObjectFromChangeSetIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) { // if the object is not instantiated, do not instantiate or cascade Object attributeValue = getAttributeValueFromObject(object); if (attributeValue != null && getIndirectionPolicy().objectIsInstantiated(attributeValue)) { Object cloneObjectCollection = getRealCollectionAttributeValueFromObject(object, uow); ContainerPolicy cp = getContainerPolicy(); for (Object cloneIter = cp.iteratorFor(cloneObjectCollection); cp.hasNext(cloneIter);) { Object referencedObject = cp.next(cloneIter, uow); if (referencedObject != null && !visitedObjects.containsKey(referencedObject)) { visitedObjects.put(referencedObject, referencedObject); ObjectBuilder builder = getReferenceDescriptor(referencedObject.getClass(), uow).getObjectBuilder(); builder.cascadePerformRemovePrivateOwnedObjectFromChangeSet(referencedObject, uow, visitedObjects); } } } }
/** * INTERNAL: * The mapping clones itself to create deep copy. */ @Override public Object clone() { AggregateCollectionMapping mappingObject = (AggregateCollectionMapping)super.clone(); mappingObject.setTargetForeignKeyToSourceKeys(new HashMap(getTargetForeignKeyToSourceKeys())); mappingObject.setSourceKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(getSourceKeyFields())); mappingObject.setTargetForeignKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(getTargetForeignKeyFields())); mappingObject.aggregateToSourceFields = new HashMap(this.aggregateToSourceFields); mappingObject.nestedAggregateToSourceFields = new HashMap(this.nestedAggregateToSourceFields); if(updateListOrderFieldQuery != null) { mappingObject.updateListOrderFieldQuery = this.updateListOrderFieldQuery; } if(bulkUpdateListOrderFieldQuery != null) { mappingObject.bulkUpdateListOrderFieldQuery = this.bulkUpdateListOrderFieldQuery; } if(pkUpdateListOrderFieldQuery != null) { mappingObject.pkUpdateListOrderFieldQuery = this.pkUpdateListOrderFieldQuery; } return mappingObject; }
/** * INTERNAL: * The foreign keys and the primary key names are converted to DatabaseFields and stored. The source keys * are not specified by the user so primary keys are extracted from the reference descriptor. */ protected void initializeTargetForeignKeyToSourceKeysWithDefaults(AbstractSession session) throws DescriptorException { if (getTargetForeignKeyFields().isEmpty()) { throw DescriptorException.noTargetForeignKeysSpecified(this); } List<DatabaseField> sourceKeys = getDescriptor().getPrimaryKeyFields(); setSourceKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(sourceKeys)); for (int index = 0; index < getTargetForeignKeyFields().size(); index++) { DatabaseField foreignKeyfield = getTargetForeignKeyFields().get(index); foreignKeyfield = getReferenceDescriptor().buildField(foreignKeyfield); getTargetForeignKeyFields().set(index, foreignKeyfield); } if (getTargetForeignKeyFields().size() != sourceKeys.size()) { throw DescriptorException.targetForeignKeysSizeMismatch(this); } for (int index = 0; index < getTargetForeignKeyFields().size(); index++) { getTargetForeignKeyToSourceKeys().put(getTargetForeignKeyFields().get(index), sourceKeys.get(index)); } }
/** * INTERNAL: * The message is passed to its reference class descriptor. */ @Override public void preInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException { if (isReadOnly()) { return; } Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); int index = 0; // pre-insert each object one by one ContainerPolicy cp = getContainerPolicy(); for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) { Object wrappedObject = cp.nextEntry(iter, query.getSession()); Object object = cp.unwrapIteratorResult(wrappedObject); InsertObjectQuery insertQuery = getAndPrepareModifyQueryForInsert(query, object); ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(wrappedObject, query.getSession()), insertQuery.getModifyRow()); if(this.listOrderField != null) { insertQuery.getModifyRow().add(this.listOrderField, index++); } // aggregates do not actually use a query to write to the database so the pre-write must be called here executeEvent(DescriptorEventManager.PreWriteEvent, insertQuery); executeEvent(DescriptorEventManager.PreInsertEvent, insertQuery); getReferenceDescriptor(object.getClass(), query.getSession()).getQueryManager().preInsert(insertQuery); cp.propogatePreInsert(query, wrappedObject); } }
if (isReadOnly()) { return; Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); ContainerPolicy containerPolicy = getContainerPolicy(); if (containerPolicy.propagatesEventsToCollection() || mustDeleteReferenceObjectsOneByOne()) { for (Object iter = containerPolicy.iteratorFor(objects); containerPolicy.hasNext(iter);) { Object wrappedObject = containerPolicy.nextEntry(iter, query.getSession()); extraData.put(this.listOrderField, index++); prepareModifyQueryForDelete(query, deleteQuery, wrappedObject, extraData); query.getSession().executeQuery(deleteQuery, deleteQuery.getTranslationRow()); containerPolicy.propogatePreDelete(query, wrappedObject); verifyDeleteForUpdate(query); deleteAll(query, objects);
Object firstCollection = getRealCollectionAttributeValueFromObject(firstObject, session); Object secondCollection = getRealCollectionAttributeValueFromObject(secondObject, session); if(this.listOrderField != null) { return this.compareLists((List)firstCollection, (List)secondCollection, session); ContainerPolicy containerPolicy = getContainerPolicy(); if (getReferenceDescriptor().getObjectBuilder().compareObjects(firstAggregateObject, secondAggregateObject, session)) { break;
public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects){ Object cloneAttribute = getAttributeValueFromObject(object); if ((cloneAttribute == null)) { return; if (usesIndirection() && (!mustDeleteReferenceObjectsOneByOne())) { if (!this.indirectionPolicy.objectIsInstantiated(cloneAttribute)) { return; ContainerPolicy cp = getContainerPolicy(); Object cloneObjectCollection = null; cloneObjectCollection = getRealCollectionAttributeValueFromObject(object, uow); Object cloneIter = cp.iteratorFor(cloneObjectCollection); while (cp.hasNext(cloneIter)) { uow.getCascadeDeleteObjects().add(nextObject); builder = getReferenceDescriptor(nextObject.getClass(), uow).getObjectBuilder(); builder.cascadePerformRemove(nextObject, uow, visitedObjects); cp.cascadePerformRemoveIfRequired(wrappedObject, uow, visitedObjects);
/** * INTERNAL: * Checks if object is deleted from the database or not. */ @Override public boolean verifyDelete(Object object, AbstractSession session) throws DatabaseException { // Row is built for translation if (isReadOnly()) { return true; } AbstractRecord row = getDescriptor().getObjectBuilder().buildRowForTranslation(object, session); Object value = session.executeQuery(getSelectionQuery(), row); return getContainerPolicy().isEmpty(value); }
/** * INTERNAL: * Insert privately owned parts */ @Override public void postInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException { if (isReadOnly()) { return; } Object objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); int index = 0; // insert each object one by one ContainerPolicy cp = getContainerPolicy(); for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) { Object wrappedObject = cp.nextEntry(iter, query.getSession()); Object object = cp.unwrapIteratorResult(wrappedObject); InsertObjectQuery insertQuery = getAndPrepareModifyQueryForInsert(query, object); ContainerPolicy.copyMapDataToRow(cp.getKeyMappingDataForWriteQuery(wrappedObject, query.getSession()), insertQuery.getModifyRow()); if(this.listOrderField != null) { insertQuery.getModifyRow().add(this.listOrderField, index++); } query.getSession().executeQuery(insertQuery, insertQuery.getTranslationRow()); cp.propogatePostInsert(query, wrappedObject); } }
/** * Add the foreign key to the aggregate collection mapping target table. * Also add listOrderField if specified. */ private void createAggregateTargetTable(AggregateCollectionMapping mapping) { TableDefinition targTblDef = getTableDefFromDBTable(mapping.getReferenceDescriptor().getDefaultTable()); addFieldsForMappedKeyMapContainerPolicy(mapping.getContainerPolicy(), targTblDef); Iterator aggregateFieldIterator = mapping.getReferenceDescriptor().getFields().iterator(); while (aggregateFieldIterator.hasNext()) { DatabaseField dbField = (DatabaseField) aggregateFieldIterator.next(); //add the target foreign key field definition to the table definition targTblDef.addField(getFieldDefFromDBField(dbField, false)); } //unlike normal one-to-many mapping, aggregate collection mapping does not have 1:1 back reference //mapping, so the target foreign key fields are not stored in the target descriptor. Iterator targFKIter = mapping.getTargetForeignKeyFields().iterator(); while (targFKIter.hasNext()) { DatabaseField dbField = (DatabaseField) targFKIter.next(); //add the target foreign key field definition to the table definition targTblDef.addField(getFieldDefFromDBField(dbField, false)); } if(mapping.getListOrderField() != null) { getTableDefFromDBTable(mapping.getListOrderField().getTable()).addField(getFieldDefFromDBField(mapping.getListOrderField(), false)); } }
/** * INTERNAL: * return the aggregate Record with the primary keys from the source table and target table */ public AbstractRecord getAggregateRow(ObjectLevelModifyQuery query, Object object) { Vector referenceObjectKeys = getReferenceObjectKeys(query); AbstractRecord aggregateRow = new DatabaseRecord(); Vector keys = getTargetForeignKeyFields(); for (int keyIndex = 0; keyIndex < keys.size(); keyIndex++) { aggregateRow.put(keys.elementAt(keyIndex), referenceObjectKeys.elementAt(keyIndex)); } getReferenceDescriptor(object.getClass(), query.getSession()).getObjectBuilder().buildRow(aggregateRow, object, query.getSession(), WriteType.UNDEFINED); return aggregateRow; }
/** * INTERNAL: * setup the modifyQuery for pre delete */ public void prepareModifyQueryForDelete(ObjectLevelModifyQuery originalQuery, ObjectLevelModifyQuery modifyQuery, Object wrappedObject, Map extraData) { Object object = getContainerPolicy().unwrapIteratorResult(wrappedObject); AbstractRecord aggregateRow = getAggregateRow(originalQuery, object); ContainerPolicy.copyMapDataToRow(containerPolicy.getKeyMappingDataForWriteQuery(wrappedObject, modifyQuery.getSession()), aggregateRow); if(this.listOrderField != null && extraData != null) { aggregateRow.put(this.listOrderField, extraData.get(this.listOrderField)); } modifyQuery.setObject(object); modifyQuery.setDescriptor(getReferenceDescriptor(object.getClass(), originalQuery.getSession())); modifyQuery.setPrimaryKey(getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromRow(aggregateRow, originalQuery.getSession())); modifyQuery.setModifyRow(aggregateRow); modifyQuery.setTranslationRow(aggregateRow); modifyQuery.setSession(originalQuery.getSession()); if (originalQuery.shouldCascadeOnlyDependentParts()) { //This query is the result of being in a UnitOfWork therefor use the Aggregate Collection //specific cascade policy to prevent cascading the delete now modifyQuery.setCascadePolicy(DatabaseQuery.CascadeAggregateDelete); } else { modifyQuery.setCascadePolicy(originalQuery.getCascadePolicy()); } modifyQuery.dontMaintainCache(); }
ContainerPolicy cp = getContainerPolicy(); Object cloneIter = cp.iteratorFor(cloneCollection); Vector collectionChanges = new Vector(2); ObjectChangeSet changes = getReferenceDescriptor(aggregateObject.getClass(), session).getObjectBuilder().compareForChange(aggregateObject, null, (UnitOfWorkChangeSet)owner.getUOWChangeSet(), session); changes.setNewKey(cp.keyFromIterator(cloneIter)); collectionChanges.addElement(changes); changeRecord.setAttribute(getAttributeName()); changeRecord.setMapping(this); changeRecord.setChangedValues(collectionChanges); getContainerPolicy().compareCollectionsForChange(backupCollection, cloneCollection, changeRecord, session, remoteReferenceDescriptor);
/** * INTERNAL: * setup the modifyQuery for post insert/update and pre delete */ public InsertObjectQuery getAndPrepareModifyQueryForInsert(ObjectLevelModifyQuery originalQuery, Object object) { AbstractSession session = originalQuery.getSession(); ClassDescriptor objReferenceDescriptor = getReferenceDescriptor(object.getClass(), session); InsertObjectQuery insertQuery = getInsertObjectQuery(session, objReferenceDescriptor); insertQuery.setObject(object); insertQuery.setDescriptor(objReferenceDescriptor); AbstractRecord targetForeignKeyRow = new DatabaseRecord(); Vector referenceObjectKeys = getReferenceObjectKeys(originalQuery); for (int keyIndex = 0; keyIndex < getTargetForeignKeyFields().size(); keyIndex++) { targetForeignKeyRow.put(getTargetForeignKeyFields().elementAt(keyIndex), referenceObjectKeys.elementAt(keyIndex)); } insertQuery.setModifyRow(targetForeignKeyRow); insertQuery.setTranslationRow(targetForeignKeyRow); insertQuery.setSession(session); insertQuery.setCascadePolicy(originalQuery.getCascadePolicy()); insertQuery.dontMaintainCache(); // For bug 2863721 must set a backup clone for compatibility with // old event mechanism, even though for AggregateCollections there is no // way to get a backup directly from a clone. if (session.isUnitOfWork()) { Object backupAttributeValue = getReferenceDescriptor(object.getClass(), session).getObjectBuilder().buildNewInstance(); insertQuery.setBackupClone(backupAttributeValue); } return insertQuery; }
/** * INTERNAL: * Extract the source primary key value from the target row. * Used for batch reading, most following same order and fields as in the mapping. */ protected Vector extractKeyFromTargetRow(AbstractRecord row, AbstractSession session) { Vector key = new Vector(getTargetForeignKeyFields().size()); for (int index = 0; index < getTargetForeignKeyFields().size(); index++) { DatabaseField targetField = getTargetForeignKeyFields().elementAt(index); DatabaseField sourceField = getSourceKeyFields().elementAt(index); Object value = row.get(targetField); // Must ensure the classification gets a cache hit. try { value = session.getDatasourcePlatform().getConversionManager().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(sourceField)); } catch (ConversionException e) { throw ConversionException.couldNotBeConverted(this, getDescriptor(), e); } key.addElement(value); } return key; }