/** INTERNAL: If any of the references objects has changed, write out all the keys. */
  public void writeFromObjectIntoRowForUpdate(WriteObjectQuery writeQuery, AbstractRecord row)
      throws DescriptorException {
    if (!this.isAttributeValueInstantiatedOrChanged(writeQuery.getObject())) {
      return;
    }

    AbstractSession session = writeQuery.getSession();

    if (session.isUnitOfWork()) {
      // PRS2074 fix for "traditional" Indirection
      Object collection1 =
          this.getRealCollectionAttributeValueFromObject(writeQuery.getObject(), session);
      Object collection2 =
          this.getRealCollectionAttributeValueFromObject(writeQuery.getBackupClone(), session);
      if (this.compareObjectsWithoutPrivateOwned(collection1, collection2, session)) {
        return; // nothing has changed - don't put anything in the row
      }
    }
    this.writeFromObjectIntoRow(writeQuery.getObject(), row, session);
  }
  /** INTERNAL: Update the privately owned parts. */
  public void preUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
    if (!this.isForeignKeyRelationship()) {
      return;
    }

    if (!this.shouldObjectModifyCascadeToParts(query)) {
      return;
    }

    // if the target objects are not instantiated, they could not have been changed....
    if (!this.isAttributeValueInstantiatedOrChanged(query.getObject())) {
      return;
    }

    // manage objects added and removed from the collection
    Object objectsInMemory =
        this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
    Object objectsInDB = this.readPrivateOwnedForObject(query);

    this.compareObjectsAndWrite(objectsInDB, objectsInMemory, query);
  }
  /** INTERNAL: Insert privately owned parts */
  public void preInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
    if (!this.isForeignKeyRelationship()) {
      return;
    }

    if (!this.shouldObjectModifyCascadeToParts(query)) {
      return;
    }

    // only cascade dependents in UOW
    if (query.shouldCascadeOnlyDependentParts()) {
      return;
    }

    Object objects =
        this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());

    // insert each object one by one
    ContainerPolicy cp = this.getContainerPolicy();
    for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter); ) {
      Object object = cp.next(iter, query.getSession());
      if (this.isPrivateOwned()) {
        // no need to set changeset here as insert is just a copy of the object anyway
        InsertObjectQuery insertQuery = new InsertObjectQuery();
        insertQuery.setIsExecutionClone(true);
        insertQuery.setObject(object);
        insertQuery.setCascadePolicy(query.getCascadePolicy());
        query.getSession().executeQuery(insertQuery);
      } else {
        // This will happen in a unit of work or cascaded query.
        // This is done only for persistence by reachability and is not required if the targets are
        // in the queue anyway
        // Avoid cycles by checking commit manager, this is allowed because there is no dependency.
        if (!query.getSession().getCommitManager().isCommitInPreModify(object)) {
          WriteObjectQuery writeQuery = new WriteObjectQuery();
          writeQuery.setIsExecutionClone(true);
          if (query.getSession().isUnitOfWork()) {
            UnitOfWorkChangeSet uowChangeSet =
                (UnitOfWorkChangeSet)
                    ((UnitOfWorkImpl) query.getSession()).getUnitOfWorkChangeSet();
            if (uowChangeSet != null) {
              writeQuery.setObjectChangeSet(
                  (ObjectChangeSet) uowChangeSet.getObjectChangeSetForClone(object));
            }
          }
          writeQuery.setObject(object);
          writeQuery.setCascadePolicy(query.getCascadePolicy());
          query.getSession().executeQuery(writeQuery);
        }
      }
    }
  }
  /** INTERNAL: Insert privately owned parts */
  public void preInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
    // Checks if privately owned parts should be inserted or not.
    if (!shouldObjectModifyCascadeToParts(query)) {
      return;
    }

    // Get the privately owned parts
    Object object = getRealAttributeValueFromObject(query.getObject(), query.getSession());

    if (object == null) {
      return;
    }

    if (isPrivateOwned()) {
      // No need to set changeSet as insert is a straight copy anyway
      InsertObjectQuery insertQuery = new InsertObjectQuery();
      insertQuery.setIsExecutionClone(true);
      insertQuery.setObject(object);
      insertQuery.setCascadePolicy(query.getCascadePolicy());
      query.getSession().executeQuery(insertQuery);
    } else {
      ObjectChangeSet changeSet = null;
      UnitOfWorkChangeSet uowChangeSet = null;
      if (query.getSession().isUnitOfWork()
          && (((UnitOfWorkImpl) query.getSession()).getUnitOfWorkChangeSet() != null)) {
        uowChangeSet =
            (UnitOfWorkChangeSet) ((UnitOfWorkImpl) query.getSession()).getUnitOfWorkChangeSet();
        changeSet = (ObjectChangeSet) uowChangeSet.getObjectChangeSetForClone(object);
      }
      WriteObjectQuery writeQuery = new WriteObjectQuery();
      writeQuery.setIsExecutionClone(true);
      writeQuery.setObject(object);
      writeQuery.setObjectChangeSet(changeSet);
      writeQuery.setCascadePolicy(query.getCascadePolicy());
      query.getSession().executeQuery(writeQuery);
    }
  }
  /** INTERNAL: Update privately owned parts */
  public void preUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
    if (!isAttributeValueInstantiated(query.getObject())) {
      return;
    }

    if (isPrivateOwned()) {
      Object objectInDatabase = readPrivateOwnedForObject(query);
      if (objectInDatabase != null) {
        query.setProperty(this, objectInDatabase);
      }
    }

    if (!shouldObjectModifyCascadeToParts(query)) {
      return;
    }

    // Get the privately owned parts in the memory
    Object object = getRealAttributeValueFromObject(query.getObject(), query.getSession());
    if (object != null) {
      ObjectChangeSet changeSet = null;
      UnitOfWorkChangeSet uowChangeSet = null;
      if (query.getSession().isUnitOfWork()
          && (((UnitOfWorkImpl) query.getSession()).getUnitOfWorkChangeSet() != null)) {
        uowChangeSet =
            (UnitOfWorkChangeSet) ((UnitOfWorkImpl) query.getSession()).getUnitOfWorkChangeSet();
        changeSet = (ObjectChangeSet) uowChangeSet.getObjectChangeSetForClone(object);
      }
      WriteObjectQuery writeQuery = new WriteObjectQuery();
      writeQuery.setIsExecutionClone(true);
      writeQuery.setObject(object);
      writeQuery.setObjectChangeSet(changeSet);
      writeQuery.setCascadePolicy(query.getCascadePolicy());
      query.getSession().executeQuery(writeQuery);
    }
  }