/** Delete all of the objects with the matching class. */ public void deleteAllObjects(Class theClass, List objects, AbstractSession session) { ClassDescriptor descriptor = null; if (((UnitOfWorkImpl) session).shouldOrderUpdates()) { // bug 331064 - Sort the delete order objects = sort(theClass, objects); } int size = objects.size(); for (int index = 0; index < size; index++) { Object objectToDelete = objects.get(index); if (objectToDelete.getClass() == theClass) { if (descriptor == null) { descriptor = session.getDescriptor(theClass); } // PERF: Get the descriptor query, to avoid extra query creation. DeleteObjectQuery deleteQuery = descriptor.getQueryManager().getDeleteQuery(); if (deleteQuery == null) { deleteQuery = new DeleteObjectQuery(); deleteQuery.setDescriptor(descriptor); } else { // Ensure original query has been prepared. deleteQuery.checkPrepare(session, deleteQuery.getTranslationRow()); deleteQuery = (DeleteObjectQuery) deleteQuery.clone(); } deleteQuery.setIsExecutionClone(true); deleteQuery.setObject(objectToDelete); session.executeQuery(deleteQuery); } } }
/** * delete all of the objects as a single transaction. This should delete the object in the correct * order to maintain referential integrity. */ public void deleteAllObjects(List objects) throws RuntimeException, DatabaseException, OptimisticLockException { this.isActive = true; AbstractSession session = getSession(); session.beginTransaction(); try { // PERF: Optimize single object case. if (objects.size() == 1) { deleteAllObjects(objects.get(0).getClass(), objects, session); } else { List commitOrder = getCommitOrder(); for (int orderIndex = commitOrder.size() - 1; orderIndex >= 0; orderIndex--) { Class theClass = (Class) commitOrder.get(orderIndex); deleteAllObjects(theClass, objects, session); } } session.commitTransaction(); } catch (RuntimeException exception) { try { session.rollbackTransaction(); } catch (Exception ignore) { } throw exception; } finally { reinitialize(); this.isActive = false; } }
/** * Commit all of the objects of the class type in the change set. This allows for the order of the * classes to be processed optimally. */ protected void commitNewObjectsForClassWithChangeSet( UnitOfWorkChangeSet uowChangeSet, Class theClass) { Map<ObjectChangeSet, ObjectChangeSet> newObjectChangesList = uowChangeSet.getNewObjectChangeSets().get(theClass); if (newObjectChangesList != null) { // may be no changes for that class type. AbstractSession session = getSession(); ClassDescriptor descriptor = session.getDescriptor(theClass); List<ObjectChangeSet> newChangeSets = new ArrayList(newObjectChangesList.values()); int size = newChangeSets.size(); for (int index = 0; index < size; index++) { ObjectChangeSet changeSetToWrite = newChangeSets.get(index); Object objectToWrite = changeSetToWrite.getUnitOfWorkClone(); if (!isProcessedCommit(objectToWrite)) { // PERF: Get the descriptor query, to avoid extra query creation. InsertObjectQuery commitQuery = descriptor.getQueryManager().getInsertQuery(); if (commitQuery == null) { commitQuery = new InsertObjectQuery(); commitQuery.setDescriptor(descriptor); } else { // Ensure original query has been prepared. commitQuery.checkPrepare(session, commitQuery.getTranslationRow()); commitQuery = (InsertObjectQuery) commitQuery.clone(); } commitQuery.setIsExecutionClone(true); commitQuery.setObjectChangeSet(changeSetToWrite); commitQuery.setObject(objectToWrite); commitQuery.cascadeOnlyDependentParts(); commitQuery.setModifyRow(null); session.executeQuery(commitQuery); } uowChangeSet.putNewObjectInChangesList(changeSetToWrite, session); } } }
/** * INTERNAL: Execute the query. Get the rows and build the object from the rows. * * @exception DatabaseException - an error has occurred on the database * @return java.lang.Object collection of objects resulting from execution of query. */ protected Object executeObjectLevelReadQuery() throws DatabaseException { Object result = null; if (getContainerPolicy().overridesRead()) { return getContainerPolicy().execute(); } if (this.descriptor.isDescriptorForInterface()) { Object returnValue = this.descriptor.getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this); setExecutionTime(System.currentTimeMillis()); return returnValue; } List rows = getQueryMechanism().selectAllRows(); setExecutionTime(System.currentTimeMillis()); // If using 1-m joins, must set all rows. if (hasJoining() && this.joinedAttributeManager.isToManyJoin()) { this.joinedAttributeManager.setDataResults(rows, this.session); } if (this.session.isUnitOfWork()) { result = registerResultInUnitOfWork( rows, (UnitOfWorkImpl) this.session, this.translationRow, true); // } else { result = getContainerPolicy().containerInstance(rows.size()); this.descriptor.getObjectBuilder().buildObjectsInto(this, rows, result); } if (this.shouldIncludeData) { ComplexQueryResult complexResult = new ComplexQueryResult(); complexResult.setResult(result); complexResult.setData(rows); return complexResult; } // Add the other (already registered) results and return them. if (getDescriptor().hasTablePerClassPolicy()) { result = containerPolicy.concatenateContainers( result, getDescriptor() .getTablePerClassPolicy() .selectAllObjectsUsingMultipleTableSubclassRead(this)); } return result; }
public List<Expression> copyDerivedExpressions(Map alreadyDone) { if (this.derivedExpressions == null) { return null; } List<Expression> derivedExpressionsCopy; synchronized (this) { derivedExpressionsCopy = new ArrayList(this.derivedExpressions); } List<Expression> result = new ArrayList(derivedExpressionsCopy.size()); for (Expression exp : derivedExpressionsCopy) { result.add(exp.copiedVersionFrom(alreadyDone)); } return result; }
// bug 331064 - Sort the delete order based on PKs. private List sort(Class theClass, List objects) { ClassDescriptor descriptor = session.getDescriptor(theClass); org.eclipse.persistence.internal.descriptors.ObjectBuilder objectBuilder = descriptor.getObjectBuilder(); int size = objects.size(); TreeMap sortedObjects = new TreeMap(); for (int index = 0; index < size; index++) { Object objectToDelete = objects.get(index); if (objectToDelete.getClass() == theClass) { sortedObjects.put( objectBuilder.extractPrimaryKeyFromObject(objectToDelete, session), objectToDelete); } } return new ArrayList(sortedObjects.values()); }
/** INTERNAL: Build the result value for the row. */ public Object buildObject(AbstractRecord row) { if (this.resultType == AUTO) { List values = row.getValues(); if (values.size() == 1) { return row.getValues().get(0); } else { return row.getValues().toArray(); } } else if (this.resultType == ARRAY) { return row.getValues().toArray(); } else if (this.resultType == ATTRIBUTE) { // Use get with field for XML records. Object value = row.get(row.getFields().get(0)); if (getValueConverter() != null) { value = getValueConverter().convertDataValueToObjectValue(value, this.session); } return value; } return row; }
/** * INTERNAL: The results are *not* in a cursor, build the collection. Cache the results in * temporaryCachedQueryResults. */ protected Object executeNonCursor() throws DatabaseException { Vector rows = getQueryMechanism().executeSelect(); Object results = null; if (this.resultType == MAP) { results = getContainerPolicy().buildContainerFromVector(rows, this.session); } else if (this.resultType == VALUE) { if (!rows.isEmpty()) { AbstractRecord record = (AbstractRecord) rows.get(0); // Use get with field for XML records. results = record.get(record.getFields().get(0)); if (getValueConverter() != null) { results = getValueConverter().convertDataValueToObjectValue(results, this.session); } } } else { int size = rows.size(); ContainerPolicy containerPolicy = getContainerPolicy(); results = containerPolicy.containerInstance(size); if (containerPolicy.shouldAddAll()) { if (size > 0) { List values = new ArrayList(size); for (int index = 0; index < size; index++) { AbstractRecord row = (AbstractRecord) rows.get(index); Object value = buildObject(row); values.add(value); } containerPolicy.addAll(values, results, this.session, rows, this); } } else { for (int index = 0; index < size; index++) { AbstractRecord row = (AbstractRecord) rows.get(index); Object value = buildObject(row); containerPolicy.addInto(value, results, this.session, row, this); } } } // Bug 6135563 - cache DataReadQuery results verbatim, as ObjectBuilder is not invoked cacheResult(results); return results; }
/** * INTERNAL: Used in case outer joins should be printed in FROM clause. Each of the additional * tables mapped to expressions that joins it. */ public Map additionalExpressionCriteriaMap() { if (getDescriptor() == null) { return null; } HashMap tablesJoinExpressions = new HashMap(); Vector tables = getDescriptor().getTables(); // skip the main table - start with i=1 int tablesSize = tables.size(); if (shouldUseOuterJoin()) { for (int i = 1; i < tablesSize; i++) { DatabaseTable table = (DatabaseTable) tables.elementAt(i); Expression joinExpression = (Expression) getDescriptor().getQueryManager().getTablesJoinExpressions().get(table); joinExpression = getBaseExpression().twist(joinExpression, this); tablesJoinExpressions.put(table, joinExpression); } } if (isUsingOuterJoinForMultitableInheritance()) { List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables(); tablesSize = childrenTables.size(); for (int i = 0; i < tablesSize; i++) { DatabaseTable table = (DatabaseTable) childrenTables.get(i); Expression joinExpression = (Expression) getDescriptor() .getInheritancePolicy() .getChildrenTablesJoinExpressions() .get(table); joinExpression = getBaseExpression().twist(joinExpression, this); tablesJoinExpressions.put(table, joinExpression); } } return tablesJoinExpressions; }
/** * INTERNAL: Used in case outer joins should be printed in FROM clause. Each of the additional * tables mapped to expressions that joins it. */ public Map additionalExpressionCriteriaMap() { if (getDescriptor() == null) { return null; } HashMap tablesJoinExpressions = null; if (isUsingOuterJoinForMultitableInheritance()) { tablesJoinExpressions = new HashMap(); List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables(); for (int i = 0; i < childrenTables.size(); i++) { DatabaseTable table = (DatabaseTable) childrenTables.get(i); Expression joinExpression = getDescriptor().getInheritancePolicy().getChildrenTablesJoinExpressions().get(table); if (getBaseExpression() != null) { joinExpression = getBaseExpression().twist(joinExpression, this); } else { joinExpression = twist(joinExpression, this); } tablesJoinExpressions.put(table, joinExpression); } } return tablesJoinExpressions; }
/** * INTERNAL: Parses an expression to return the first non-AggregateObjectMapping expression after * the base ExpressionBuilder. This is used by joining and batch fetch to get the list of mappings * that really need to be processed (non-aggregates). * * @param aggregateMappingsEncountered - collection of aggregateObjectMapping expressions * encountered in the returned expression between the first expression and the * ExpressionBuilder * @return first non-AggregateObjectMapping expression after the base ExpressionBuilder from the * fullExpression */ public ObjectExpression getFirstNonAggregateExpressionAfterExpressionBuilder( List aggregateMappingsEncountered) { boolean done = false; ObjectExpression baseExpression = this; ObjectExpression prevExpression = this; while (!baseExpression.getBaseExpression().isExpressionBuilder() && !done) { baseExpression = (ObjectExpression) baseExpression.getBaseExpression(); while (!baseExpression.isExpressionBuilder() && baseExpression.getMapping().isAggregateObjectMapping()) { aggregateMappingsEncountered.add(baseExpression.getMapping()); baseExpression = (ObjectExpression) baseExpression.getBaseExpression(); } if (baseExpression.isExpressionBuilder()) { done = true; // use the one closest to the expression builder that wasn't an aggregate baseExpression = prevExpression; } else { prevExpression = baseExpression; } } return baseExpression; }
/** * INTERNAL: All objects queried via a UnitOfWork get registered here. If the query went to the * database. * * <p>Involves registering the query result individually and in totality, and hence refreshing / * conforming is done here. * * @param result may be collection (read all) or an object (read one), or even a cursor. If in * transaction the shared cache will be bypassed, meaning the result may not be originals from * the parent but raw database rows. * @param unitOfWork the unitOfWork the result is being registered in. * @param arguments the original arguments/parameters passed to the query execution. Used by * conforming * @param buildDirectlyFromRows If in transaction must construct a registered result from raw * database rows. * @return the final (conformed, refreshed, wrapped) UnitOfWork query result */ public Object registerResultInUnitOfWork( Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) { // For bug 2612366: Conforming results in UOW extremely slow. // Replacing results with registered versions in the UOW is a part of // conforming and is now done while conforming to maximize performance. if (shouldConformResultsInUnitOfWork() || this.descriptor.shouldAlwaysConformResultsInUnitOfWork()) { return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows); } // When building directly from rows, one of the performance benefits // is that we no longer have to wrap and then unwrap the originals. // result is just a vector, not a collection of wrapped originals. // Also for cursors the initial connection is automatically registered. if (buildDirectlyFromRows) { List<AbstractRecord> rows = (List<AbstractRecord>) result; ContainerPolicy cp = getContainerPolicy(); int size = rows.size(); Object clones = cp.containerInstance(size); for (int index = 0; index < size; index++) { AbstractRecord row = rows.get(index); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (row != null) { Object clone = buildObject(row); cp.addInto(clone, clones, unitOfWork, row, this); } } return clones; } ContainerPolicy cp; Cursor cursor = null; // If the query is redirected then the collection returned might no longer // correspond to the original container policy. CR#2342-S.M. if (getRedirector() != null) { cp = ContainerPolicy.buildPolicyFor(result.getClass()); } else { cp = getContainerPolicy(); } // In the case of cursors just register the initially read collection. if (cp.isCursorPolicy()) { cursor = (Cursor) result; // In nested UnitOfWork session might have been session of the parent. cursor.setSession(unitOfWork); cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class); result = cursor.getObjectCollection(); } Object clones = cp.containerInstance(cp.sizeFor(result)); AbstractSession sessionToUse = unitOfWork.getParent(); for (Object iter = cp.iteratorFor(result); cp.hasNext(iter); ) { Object object = cp.next(iter, sessionToUse); Object clone = registerIndividualResult(object, unitOfWork, this.joinedAttributeManager); cp.addInto(clone, clones, unitOfWork); } if (cursor != null) { cursor.setObjectCollection((Vector) clones); return cursor; } else { return clones; } }
protected boolean hasObjectsToDelete() { return ((objectsToDelete != null) && (!objectsToDelete.isEmpty())); }
/** * Commit all of the objects as a single transaction. This should commit the object in the correct * order to maintain referential integrity. */ public void commitAllObjectsWithChangeSet(UnitOfWorkChangeSet uowChangeSet) throws RuntimeException, DatabaseException, OptimisticLockException { reinitialize(); this.isActive = true; this.session.beginTransaction(); try { // PERF: if the number of classes in the project is large this loop can be a perf issue. // If only one class types changed, then avoid loop. if ((uowChangeSet.getObjectChanges().size() + uowChangeSet.getNewObjectChangeSets().size()) <= 1) { Iterator<Class> classes = uowChangeSet.getNewObjectChangeSets().keySet().iterator(); if (classes.hasNext()) { Class theClass = classes.next(); commitNewObjectsForClassWithChangeSet(uowChangeSet, theClass); } classes = uowChangeSet.getObjectChanges().keySet().iterator(); if (classes.hasNext()) { Class theClass = classes.next(); commitChangedObjectsForClassWithChangeSet(uowChangeSet, theClass); } } else { // The commit order is all of the classes ordered by dependencies, this is done for deadlock // avoidance. List commitOrder = getCommitOrder(); int size = commitOrder.size(); for (int index = 0; index < size; index++) { Class theClass = (Class) commitOrder.get(index); commitAllObjectsForClassWithChangeSet(uowChangeSet, theClass); } } if (hasDeferredCalls()) { // Perform all batched up calls, done to avoid dependencies. for (List<Object[]> calls : this.deferredCalls.values()) { for (Object[] argument : calls) { ((DatabaseQueryMechanism) argument[1]) .executeDeferredCall((DatasourceCall) argument[0]); } } } if (hasDataModifications()) { // Perform all batched up data modifications, done to avoid dependencies. for (Map.Entry<DatabaseMapping, List<Object[]>> entry : this.dataModifications.entrySet()) { List<Object[]> events = entry.getValue(); int size = events.size(); DatabaseMapping mapping = entry.getKey(); for (int index = 0; index < size; index++) { Object[] event = events.get(index); mapping.performDataModificationEvent(event, getSession()); } } } if (hasObjectsToDelete()) { // These are orphaned objects, to be deleted from private ownership updates. // TODO: These should be added to the unit of work deleted so they are deleted in the // correct order. List objects = getObjectsToDelete(); int size = objects.size(); reinitialize(); for (int index = 0; index < size; index++) { this.session.deleteObject(objects.get(index)); } } this.session.commitTransaction(); } catch (RuntimeException exception) { this.session.rollbackTransaction(); throw exception; } finally { reinitialize(); this.isActive = false; } }