public void noCascade(
            EventSource session,
            Object child,
            Object parent,
            EntityPersister persister,
            int propertyIndex) {
          if (child == null) {
            return;
          }
          Type type = persister.getPropertyTypes()[propertyIndex];
          if (type.isEntityType()) {
            String childEntityName =
                ((EntityType) type).getAssociatedEntityName(session.getFactory());

            if (!isInManagedState(child, session)
                && !(child
                    instanceof
                    HibernateProxy) // a proxy cannot be transient and it breaks
                                    // ForeignKeys.isTransient
                && ForeignKeys.isTransient(childEntityName, child, null, session)) {
              String parentEntiytName = persister.getEntityName();
              String propertyName = persister.getPropertyNames()[propertyIndex];
              throw new TransientObjectException(
                  "object references an unsaved transient instance - "
                      + "save the transient instance before flushing: "
                      + parentEntiytName
                      + "."
                      + propertyName
                      + " -> "
                      + childEntityName);
            }
          }
        }
  /**
   * Reads the entity hosting the association from the datastore and applies any property changes
   * from the server side.
   */
  private void updateHostingEntityIfRequired() {
    if (hostingEntity != null && hostingEntityRequiresReadAfterUpdate()) {
      EntityPersister entityPersister = getHostingEntityPersister();

      entityPersister.processUpdateGeneratedProperties(
          entityPersister.getIdentifier(hostingEntity, session),
          hostingEntity,
          new Object[entityPersister.getPropertyNames().length],
          session);
    }
  }
 private void synchronizePersisterState(Object entity, EntityPersister persister, Object[] state) {
   String[] propertyNames = persister.getPropertyNames();
   for (int i = 0; i < propertyNames.length; i++) {
     String p = propertyNames[i];
     MetaProperty metaProperty = domainMetaClass.getMetaProperty(p);
     if (ClosureEventTriggeringInterceptor.IGNORED.contains(p) || metaProperty == null) {
       continue;
     }
     Object value = metaProperty.getProperty(entity);
     state[i] = value;
     persister.setPropertyValue(entity, i, value);
   }
 }
 private void logDirtyProperties(
     Serializable id, int[] dirtyProperties, EntityPersister persister) {
   if (LOG.isTraceEnabled() && dirtyProperties != null && dirtyProperties.length > 0) {
     final String[] allPropertyNames = persister.getPropertyNames();
     final String[] dirtyPropertyNames = new String[dirtyProperties.length];
     for (int i = 0; i < dirtyProperties.length; i++) {
       dirtyPropertyNames[i] = allPropertyNames[dirtyProperties[i]];
     }
     LOG.trace(
         "Found dirty properties ["
             + MessageHelper.infoString(persister.getEntityName(), id)
             + "] : "
             + dirtyPropertyNames);
   }
 }
 protected boolean invokeInterceptor(
     SessionImplementor session,
     Object entity,
     EntityEntry entry,
     final Object[] values,
     EntityPersister persister) {
   return session
       .getInterceptor()
       .onFlushDirty(
           entity,
           entry.getId(),
           values,
           entry.getLoadedState(),
           persister.getPropertyNames(),
           persister.getPropertyTypes());
 }
  /**
   * Perform any property value substitution that is necessary (interceptor callback, version
   * initialization...)
   *
   * @param entity The entity
   * @param id The entity identifier
   * @param values The snapshot entity state
   * @param persister The entity persister
   * @param source The originating session
   * @return True if the snapshot state changed such that reinjection of the values into the entity
   *     is required.
   */
  protected boolean substituteValuesIfNecessary(
      Object entity,
      Serializable id,
      Object[] values,
      EntityPersister persister,
      SessionImplementor source) {
    boolean substitute =
        source
            .getInterceptor()
            .onSave(entity, id, values, persister.getPropertyNames(), persister.getPropertyTypes());

    // keep the existing version number in the case of replicate!
    if (persister.isVersioned()) {
      substitute =
          Versioning.seedVersion(
                  values, persister.getVersionProperty(), persister.getVersionType(), source)
              || substitute;
    }
    return substitute;
  }
Пример #7
0
  public ModWorkUnit(
      SessionImplementor sessionImplementor,
      String entityName,
      AuditConfiguration verCfg,
      Serializable id,
      EntityPersister entityPersister,
      Object[] newState,
      Object[] oldState) {
    super(sessionImplementor, entityName, verCfg, id, RevisionType.MOD);

    this.entityPersister = entityPersister;
    this.oldState = oldState;
    this.newState = newState;
    data = new HashMap<String, Object>();
    changes =
        verCfg
            .getEntCfg()
            .get(getEntityName())
            .getPropertyMapper()
            .map(sessionImplementor, data, entityPersister.getPropertyNames(), newState, oldState);
  }
  @Override
  public Set<AssociationKeyMetadata> getAllAssociationKeyMetadata() {
    Set<AssociationKeyMetadata> allAssociationKeyMetadata = new HashSet<>();

    for (CollectionPersister associationPersister : factory.getCollectionPersisters().values()) {
      allAssociationKeyMetadata.add(
          ((OgmCollectionPersister) associationPersister).getAssociationKeyMetadata());
    }

    for (EntityPersister entityPersister : factory.getEntityPersisters().values()) {
      for (String property : entityPersister.getPropertyNames()) {
        AssociationKeyMetadata inverseOneToOneAssociationKeyMetadata =
            ((OgmEntityPersister) entityPersister)
                .getInverseOneToOneAssociationKeyMetadata(property);
        if (inverseOneToOneAssociationKeyMetadata != null) {
          allAssociationKeyMetadata.add(inverseOneToOneAssociationKeyMetadata);
        }
      }
    }

    return allAssociationKeyMetadata;
  }
  /**
   * Perform the entity deletion. Well, as with most operations, does not really perform it; just
   * schedules an action/execution with the {@link org.hibernate.engine.spi.ActionQueue} for
   * execution during flush.
   *
   * @param session The originating session
   * @param entity The entity to delete
   * @param entityEntry The entity's entry in the {@link PersistenceContext}
   * @param isCascadeDeleteEnabled Is delete cascading enabled?
   * @param persister The entity persister.
   * @param transientEntities A cache of already deleted entities.
   */
  protected final void deleteEntity(
      final EventSource session,
      final Object entity,
      final EntityEntry entityEntry,
      final boolean isCascadeDeleteEnabled,
      final boolean isOrphanRemovalBeforeUpdates,
      final EntityPersister persister,
      final Set transientEntities) {

    if (LOG.isTraceEnabled()) {
      LOG.tracev(
          "Deleting {0}",
          MessageHelper.infoString(persister, entityEntry.getId(), session.getFactory()));
    }

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    final Type[] propTypes = persister.getPropertyTypes();
    final Object version = entityEntry.getVersion();

    final Object[] currentState;
    if (entityEntry.getLoadedState() == null) {
      // ie. the entity came in from update()
      currentState = persister.getPropertyValues(entity);
    } else {
      currentState = entityEntry.getLoadedState();
    }

    final Object[] deletedState = createDeletedState(persister, currentState, session);
    entityEntry.setDeletedState(deletedState);

    session
        .getInterceptor()
        .onDelete(
            entity, entityEntry.getId(), deletedState, persister.getPropertyNames(), propTypes);

    // before any callbacks, etc, so subdeletions see that this deletion happened first
    persistenceContext.setEntryStatus(entityEntry, Status.DELETED);
    final EntityKey key = session.generateEntityKey(entityEntry.getId(), persister);

    cascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);

    new ForeignKeys.Nullifier(entity, true, false, session)
        .nullifyTransientReferences(entityEntry.getDeletedState(), propTypes);
    new Nullability(session).checkNullability(entityEntry.getDeletedState(), persister, true);
    persistenceContext.getNullifiableEntityKeys().add(key);

    if (isOrphanRemovalBeforeUpdates) {
      // TODO: The removeOrphan concept is a temporary "hack" for HHH-6484.  This should be removed
      // once action/task
      // ordering is improved.
      session
          .getActionQueue()
          .addAction(
              new OrphanRemovalAction(
                  entityEntry.getId(),
                  deletedState,
                  version,
                  entity,
                  persister,
                  isCascadeDeleteEnabled,
                  session));
    } else {
      // Ensures that containing deletions happen before sub-deletions
      session
          .getActionQueue()
          .addAction(
              new EntityDeleteAction(
                  entityEntry.getId(),
                  deletedState,
                  version,
                  entity,
                  persister,
                  isCascadeDeleteEnabled,
                  session));
    }

    cascadeAfterDelete(session, persister, entity, transientEntities);

    // the entry will be removed after the flush, and will no longer
    // override the stale snapshot
    // This is now handled by removeEntity() in EntityDeleteAction
    // persistenceContext.removeDatabaseSnapshot(key);
  }
  /** Perform a dirty check, and attach the results to the event */
  protected void dirtyCheck(FlushEntityEvent event) throws HibernateException {

    final Object entity = event.getEntity();
    final Object[] values = event.getPropertyValues();
    final SessionImplementor session = event.getSession();
    final EntityEntry entry = event.getEntityEntry();
    final EntityPersister persister = entry.getPersister();
    final Serializable id = entry.getId();
    final Object[] loadedState = entry.getLoadedState();

    int[] dirtyProperties =
        session
            .getInterceptor()
            .findDirty(
                entity,
                id,
                values,
                loadedState,
                persister.getPropertyNames(),
                persister.getPropertyTypes());

    event.setDatabaseSnapshot(null);

    final boolean interceptorHandledDirtyCheck;
    boolean cannotDirtyCheck;

    if (dirtyProperties == null) {
      // Interceptor returned null, so do the dirtycheck ourself, if possible
      interceptorHandledDirtyCheck = false;

      cannotDirtyCheck = loadedState == null; // object loaded by update()
      if (!cannotDirtyCheck) {
        // dirty check against the usual snapshot of the entity
        dirtyProperties = persister.findDirty(values, loadedState, entity, session);
      } else if (entry.getStatus() == Status.DELETED
          && !event.getEntityEntry().isModifiableEntity()) {
        // A non-modifiable (e.g., read-only or immutable) entity needs to be have
        // references to transient entities set to null before being deleted. No other
        // fields should be updated.
        if (values != entry.getDeletedState()) {
          throw new IllegalStateException(
              "Entity has status Status.DELETED but values != entry.getDeletedState");
        }
        // Even if loadedState == null, we can dirty-check by comparing currentState and
        // entry.getDeletedState() because the only fields to be updated are those that
        // refer to transient entities that are being set to null.
        // - currentState contains the entity's current property values.
        // - entry.getDeletedState() contains the entity's current property values with
        //   references to transient entities set to null.
        // - dirtyProperties will only contain properties that refer to transient entities
        final Object[] currentState =
            persister.getPropertyValues(event.getEntity(), event.getSession().getEntityMode());
        dirtyProperties =
            persister.findDirty(entry.getDeletedState(), currentState, entity, session);
        cannotDirtyCheck = false;
      } else {
        // dirty check against the database snapshot, if possible/necessary
        final Object[] databaseSnapshot = getDatabaseSnapshot(session, persister, id);
        if (databaseSnapshot != null) {
          dirtyProperties = persister.findModified(databaseSnapshot, values, entity, session);
          cannotDirtyCheck = false;
          event.setDatabaseSnapshot(databaseSnapshot);
        }
      }
    } else {
      // the Interceptor handled the dirty checking
      cannotDirtyCheck = false;
      interceptorHandledDirtyCheck = true;
    }

    logDirtyProperties(id, dirtyProperties, persister);

    event.setDirtyProperties(dirtyProperties);
    event.setDirtyCheckHandledByInterceptor(interceptorHandledDirtyCheck);
    event.setDirtyCheckPossible(!cannotDirtyCheck);
  }