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; }
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); }