/** make sure user didn't mangle the id */
  public void checkId(
      Object object,
      EntityPersister persister,
      Serializable id,
      EntityMode entityMode,
      SessionImplementor session)
      throws HibernateException {

    if (id != null && id instanceof DelayedPostInsertIdentifier) {
      // this is a situation where the entity id is assigned by a post-insert generator
      // and was saved outside the transaction forcing it to be delayed
      return;
    }

    if (persister.canExtractIdOutOfEntity()) {

      Serializable oid = persister.getIdentifier(object, session);
      if (id == null) {
        throw new AssertionFailure(
            "null id in "
                + persister.getEntityName()
                + " entry (don't flush the Session after an exception occurs)");
      }
      if (!persister.getIdentifierType().isEqual(id, oid, entityMode, session.getFactory())) {
        throw new HibernateException(
            "identifier of an instance of "
                + persister.getEntityName()
                + " was altered from "
                + id
                + " to "
                + oid);
      }
    }
  }
  FromElement createElementJoin(QueryableCollection queryableCollection) throws SemanticException {
    FromElement elem;

    implied =
        true; // TODO: always true for now, but not if we later decide to support elements() in the
              // from clause
    inElementsFunction = true;
    Type elementType = queryableCollection.getElementType();
    if (!elementType.isEntityType()) {
      throw new IllegalArgumentException(
          "Cannot create element join for a collection of non-entities!");
    }
    this.queryableCollection = queryableCollection;
    SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper();
    FromElement destination = null;
    String tableAlias = null;
    EntityPersister entityPersister = queryableCollection.getElementPersister();
    tableAlias = fromClause.getAliasGenerator().createName(entityPersister.getEntityName());
    String associatedEntityName = entityPersister.getEntityName();
    EntityPersister targetEntityPersister = sfh.requireClassPersister(associatedEntityName);
    // Create the FROM element for the target (the elements of the collection).
    destination =
        createAndAddFromElement(
            associatedEntityName,
            classAlias,
            targetEntityPersister,
            (EntityType) queryableCollection.getElementType(),
            tableAlias);
    // If the join is implied, then don't include sub-classes on the element.
    if (implied) {
      destination.setIncludeSubclasses(false);
    }
    fromClause.addCollectionJoinFromElementByPath(path, destination);
    //		origin.addDestination(destination);
    // Add the query spaces.
    fromClause.getWalker().addQuerySpaces(entityPersister.getQuerySpaces());

    CollectionType type = queryableCollection.getCollectionType();
    String role = type.getRole();
    String roleAlias = origin.getTableAlias();

    String[] targetColumns = sfh.getCollectionElementColumns(role, roleAlias);
    AssociationType elementAssociationType = sfh.getElementAssociationType(type);

    // Create the join element under the from element.
    int joinType = JoinFragment.INNER_JOIN;
    JoinSequence joinSequence =
        sfh.createJoinSequence(
            implied, elementAssociationType, tableAlias, joinType, targetColumns);
    elem = initializeJoin(path, destination, joinSequence, targetColumns, origin, false);
    elem.setUseFromFragment(
        true); // The associated entity is implied, but it must be included in the FROM.
    elem.setCollectionTableAlias(roleAlias); // The collection alias is the role.
    return elem;
  }
  /**
   * Handle the given lock event.
   *
   * @param event The lock event to be handled.
   * @throws HibernateException
   */
  public void onLock(LockEvent event) throws HibernateException {

    if (event.getObject() == null) {
      throw new NullPointerException("attempted to lock null");
    }

    if (event.getLockMode() == LockMode.WRITE) {
      throw new HibernateException("Invalid lock mode for lock()");
    }

    SessionImplementor source = event.getSession();

    Object entity = source.getPersistenceContext().unproxyAndReassociate(event.getObject());
    // TODO: if object was an uninitialized proxy, this is inefficient,
    //      resulting in two SQL selects

    EntityEntry entry = source.getPersistenceContext().getEntry(entity);
    if (entry == null) {
      final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
      final Serializable id = persister.getIdentifier(entity, source.getEntityMode());
      if (!ForeignKeys.isNotTransient(event.getEntityName(), entity, Boolean.FALSE, source)) {
        throw new TransientObjectException(
            "cannot lock an unsaved transient instance: " + persister.getEntityName());
      }

      entry = reassociate(event, entity, id, persister);

      cascadeOnLock(event, persister, entity);
    }

    upgradeLock(entity, entry, event.getLockMode(), source);
  }
 public EntityEntry(
     final Status status,
     final Object[] loadedState,
     final Object rowId,
     final Serializable id,
     final Object version,
     final LockMode lockMode,
     final boolean existsInDatabase,
     final EntityPersister persister,
     final EntityMode entityMode,
     final String tenantId,
     final boolean disableVersionIncrement,
     final boolean lazyPropertiesAreUnfetched,
     final PersistenceContext persistenceContext) {
   this.status = status;
   this.previousStatus = null;
   // only retain loaded state if the status is not Status.READ_ONLY
   if (status != Status.READ_ONLY) {
     this.loadedState = loadedState;
   }
   this.id = id;
   this.rowId = rowId;
   this.existsInDatabase = existsInDatabase;
   this.version = version;
   this.lockMode = lockMode;
   this.isBeingReplicated = disableVersionIncrement;
   this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
   this.persister = persister;
   this.entityMode = entityMode;
   this.tenantId = tenantId;
   this.entityName = persister == null ? null : persister.getEntityName();
   this.persistenceContext = persistenceContext;
 }
 private void checkNaturalId(
     EntityPersister persister,
     EntityEntry entry,
     Object[] current,
     Object[] loaded,
     EntityMode entityMode,
     SessionImplementor session) {
   if (persister.hasNaturalIdentifier() && entry.getStatus() != Status.READ_ONLY) {
     Object[] snapshot = null;
     Type[] types = persister.getPropertyTypes();
     int[] props = persister.getNaturalIdentifierProperties();
     boolean[] updateable = persister.getPropertyUpdateability();
     for (int i = 0; i < props.length; i++) {
       int prop = props[i];
       if (!updateable[prop]) {
         Object loadedVal;
         if (loaded == null) {
           if (snapshot == null) {
             snapshot =
                 session.getPersistenceContext().getNaturalIdSnapshot(entry.getId(), persister);
           }
           loadedVal = snapshot[i];
         } else {
           loadedVal = loaded[prop];
         }
         if (!types[prop].isEqual(current[prop], loadedVal, entityMode)) {
           throw new HibernateException(
               "immutable natural identifier of an instance of "
                   + persister.getEntityName()
                   + " was altered");
         }
       }
     }
   }
 }
        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);
            }
          }
        }
  @SuppressWarnings("unchecked")
  @Override
  /**
   * Handle the given delete event. This is the cascaded form.
   *
   * @param event The delete event.
   * @param transientEntities The cache of entities already deleted
   * @throws HibernateException
   */
  public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
    final EventSource source = event.getSession();

    final PersistenceContext persistenceContext = source.getPersistenceContext();
    Object entity = persistenceContext.unproxyAndReassociate(event.getObject());
    EntityEntry entityEntry = persistenceContext.getEntry(entity);

    final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
    final Object version;

    if (persister.isVersioned()) {
      version = persister.getVersion(entity, source.getEntityMode());
      // Make sure version has not changed on deleted entities
      if ((entity instanceof TimelineEntity) && !((TimelineEntity) entity).isNew()) {
        if (!persister.getVersionType().isEqual(version, entityEntry.getVersion())) {
          throw new StaleObjectStateException(persister.getEntityName(), entityEntry.getId());
        }
      }
    }
    super.onDelete(event, transientEntities);
  }
 protected EntityAction(
     SessionImplementor session, Serializable id, Object instance, EntityPersister persister) {
   this.session = session;
   this.id = id;
   this.persister = persister;
   this.instance = instance;
   this.entityName = persister.getEntityName();
 }
 public void evictEntityRegion(String entityName) {
   EntityPersister p = getEntityPersister(entityName);
   if (p.hasCache()) {
     if (log.isDebugEnabled()) {
       log.debug("evicting second-level cache: " + p.getEntityName());
     }
     p.getCacheAccessStrategy().evictAll();
   }
 }
 private Object[] getDatabaseSnapshot(
     SessionImplementor session, EntityPersister persister, Serializable id) {
   if (persister.isSelectBeforeUpdateRequired()) {
     Object[] snapshot = session.getPersistenceContext().getDatabaseSnapshot(id, persister);
     if (snapshot == null) {
       // do we even really need this? the update will fail anyway....
       if (session.getFactory().getStatistics().isStatisticsEnabled()) {
         session
             .getFactory()
             .getStatisticsImplementor()
             .optimisticFailure(persister.getEntityName());
       }
       throw new StaleObjectStateException(persister.getEntityName(), id);
     }
     return snapshot;
   }
   // TODO: optimize away this lookup for entities w/o unsaved-value="undefined"
   final EntityKey entityKey = session.generateEntityKey(id, persister);
   return session.getPersistenceContext().getCachedDatabaseSnapshot(entityKey);
 }
 private void initializeAndAddFromElement(
     FromElement element,
     String className,
     String classAlias,
     EntityPersister entityPersister,
     EntityType type,
     String tableAlias) {
   if (tableAlias == null) {
     AliasGenerator aliasGenerator = fromClause.getAliasGenerator();
     tableAlias = aliasGenerator.createName(entityPersister.getEntityName());
   }
   element.initializeEntity(fromClause, className, entityPersister, type, classAlias, tableAlias);
 }
  private void evictCache(
      Object entity, EntityPersister persister, EventSource session, Object[] oldState) {
    try {
      SessionFactoryImplementor factory = persister.getFactory();

      Set<String> collectionRoles =
          factory.getCollectionRolesByEntityParticipant(persister.getEntityName());
      if (collectionRoles == null || collectionRoles.isEmpty()) {
        return;
      }
      for (String role : collectionRoles) {
        CollectionPersister collectionPersister = factory.getCollectionPersister(role);
        if (!collectionPersister.hasCache()) {
          // ignore collection if no caching is used
          continue;
        }
        // this is the property this OneToMany relation is mapped by
        String mappedBy = collectionPersister.getMappedByProperty();
        if (mappedBy != null) {
          int i = persister.getEntityMetamodel().getPropertyIndex(mappedBy);
          Serializable oldId = null;
          if (oldState != null) {
            // in case of updating an entity we perhaps have to decache 2 entity collections, this
            // is the
            // old one
            oldId = session.getIdentifier(oldState[i]);
          }
          Object ref = persister.getPropertyValue(entity, i);
          Serializable id = null;
          if (ref != null) {
            id = session.getIdentifier(ref);
          }
          // only evict if the related entity has changed
          if (id != null && !id.equals(oldId)) {
            evict(id, collectionPersister, session);
            if (oldId != null) {
              evict(oldId, collectionPersister, session);
            }
          }
        } else {
          LOG.debug("Evict CollectionRegion " + role);
          collectionPersister.getCacheAccessStrategy().evictAll();
        }
      }
    } catch (Exception e) {
      // don't let decaching influence other logic
      LOG.error("", e);
    }
  }
 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);
   }
 }
 /**
  * Determine the id to use for updating.
  *
  * @param entity The entity.
  * @param persister The entity persister
  * @param requestedId The requested identifier
  * @param session The session
  * @return The id.
  * @throws TransientObjectException If the entity is considered transient.
  */
 protected Serializable getUpdateId(
     Object entity,
     EntityPersister persister,
     Serializable requestedId,
     SessionImplementor session) {
   // use the id assigned to the instance
   Serializable id = persister.getIdentifier(entity, session);
   if (id == null) {
     // assume this is a newly instantiated transient object
     // which should be saved rather than updated
     throw new TransientObjectException(
         "The given object has a null identifier: " + persister.getEntityName());
   } else {
     return id;
   }
 }
 @Test
 public void testColumnMapping() throws Exception {
   Session session = sessionFactory.openSession();
   try {
     Map metadata = sessionFactory.getAllClassMetadata();
     for (Object o : metadata.values()) {
       EntityPersister persister = (EntityPersister) o;
       String className = persister.getEntityName();
       log.debug("Trying select * from: " + className);
       Query q = session.createQuery("from " + className + " c");
       q.iterate();
       log.debug("ok: " + className);
     }
   } finally {
     session.close();
   }
 }
  public void onPostDelete(PostDeleteEvent event) {
    EntityPersister entityPersister = event.getPersister();
    String entityName = entityPersister.getEntityName();

    if (entityName.equals(NAVIGATION_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildLoginHtml();
      jobService.buildArticleContentHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(FRIEND_LINK_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildLoginHtml();
      jobService.buildArticleContentHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(ARTICLE_CATEGORY_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildArticleContentHtml();
    } else if (entityName.equals(GOODS_CATEGORY_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(ARTICLE_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      Article article = (Article) event.getEntity();
      jobService.deleteArticleContentHtml(article.getHtmlPath(), article.getPageCount());
    } else if (entityName.equals(GOODS_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      Goods goods = (Goods) event.getEntity();
      jobService.deleteGoodsContentHtml(goods.getHtmlPath());
    } else if (entityName.equals(PRODUCT_ENTITY_NAME)) {
      Product product = (Product) event.getEntity();
      jobService.buildGoodsContentHtml(product.getGoods().getId());
    } else if (entityName.equals(COMMENT_ENTITY_NAME)) {
      Comment comment = (Comment) event.getEntity();
      jobService.buildGoodsContentHtml(comment.getGoods().getId());
    } else if (entityName.equals(INSTANT_MESSAGING_ENTITY_NAME)) {
      jobService.buildShopJs();
    }
  }
  public void onPostUpdate(PostUpdateEvent event) {
    EntityPersister entityPersister = event.getPersister();
    String entityName = entityPersister.getEntityName();
    String id = String.valueOf(event.getId());

    if (entityName.equals(NAVIGATION_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildLoginHtml();
      jobService.buildArticleContentHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(FRIEND_LINK_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildLoginHtml();
      jobService.buildArticleContentHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(ARTICLE_CATEGORY_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildArticleContentHtml();
    } else if (entityName.equals(GOODS_CATEGORY_ENTITY_NAME)) {
      jobService.buildIndexHtml();
      jobService.buildGoodsContentHtml();
    } else if (entityName.equals(ARTICLE_ENTITY_NAME)) {
      jobService.buildArticleContentHtml(id);
      jobService.buildIndexHtml();
    } else if (entityName.equals(GOODS_ENTITY_NAME)) {
      jobService.buildGoodsContentHtml(id);
      jobService.buildIndexHtml();
    } else if (entityName.equals(PRODUCT_ENTITY_NAME)) {
      Product product = (Product) event.getEntity();
      jobService.buildGoodsContentHtml(product.getGoods().getId());
    } else if (entityName.equals(COMMENT_ENTITY_NAME)) {
      Comment comment = (Comment) event.getEntity();
      jobService.buildGoodsContentHtml(comment.getGoods().getId());
    } else if (entityName.equals(INSTANT_MESSAGING_ENTITY_NAME)) {
      jobService.buildShopJs();
    }
  }
  /**
   * Prepares the save call by checking the session caches for a pre-existing entity and performing
   * any lifecycle callbacks.
   *
   * @param entity The entity to be saved.
   * @param id The id by which to save the entity.
   * @param persister The entity's persister instance.
   * @param useIdentityColumn Is an identity column being used?
   * @param anything Generally cascade-specific information.
   * @param source The session from which the event originated.
   * @param requiresImmediateIdAccess does the event context require access to the identifier
   *     immediately after execution of this method (if not, post-insert style id generators may be
   *     postponed if we are outside a transaction).
   * @return The id used to save the entity; may be null depending on the type of id generator used
   *     and the requiresImmediateIdAccess value
   */
  protected Serializable performSave(
      Object entity,
      Serializable id,
      EntityPersister persister,
      boolean useIdentityColumn,
      Object anything,
      EventSource source,
      boolean requiresImmediateIdAccess) {

    if (LOG.isTraceEnabled()) {
      LOG.tracev("Saving {0}", MessageHelper.infoString(persister, id, source.getFactory()));
    }

    final EntityKey key;
    if (!useIdentityColumn) {
      key = source.generateEntityKey(id, persister);
      Object old = source.getPersistenceContext().getEntity(key);
      if (old != null) {
        if (source.getPersistenceContext().getEntry(old).getStatus() == Status.DELETED) {
          source.forceFlush(source.getPersistenceContext().getEntry(old));
        } else {
          throw new NonUniqueObjectException(id, persister.getEntityName());
        }
      }
      persister.setIdentifier(entity, id, source);
    } else {
      key = null;
    }

    if (invokeSaveLifecycle(entity, persister, source)) {
      return id; // EARLY EXIT
    }

    return performSaveOrReplicate(
        entity, key, persister, useIdentityColumn, anything, source, requiresImmediateIdAccess);
  }
  /**
   * Perform the second step of 2-phase load. Fully initialize the entity instance.
   *
   * <p>After processing a JDBC result set, we "resolve" all the associations between the entities
   * which were instantiated and had their state "hydrated" into an array
   */
  public static void initializeEntity(
      final Object entity,
      final boolean readOnly,
      final SessionImplementor session,
      final PreLoadEvent preLoadEvent,
      final PostLoadEvent postLoadEvent)
      throws HibernateException {

    // TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!)

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    EntityEntry entityEntry = persistenceContext.getEntry(entity);
    if (entityEntry == null) {
      throw new AssertionFailure("possible non-threadsafe access to the session");
    }
    EntityPersister persister = entityEntry.getPersister();
    Serializable id = entityEntry.getId();
    Object[] hydratedState = entityEntry.getLoadedState();

    if (log.isDebugEnabled())
      log.debug(
          "resolving associations for "
              + MessageHelper.infoString(persister, id, session.getFactory()));

    Type[] types = persister.getPropertyTypes();
    for (int i = 0; i < hydratedState.length; i++) {
      final Object value = hydratedState[i];
      if (value != LazyPropertyInitializer.UNFETCHED_PROPERTY
          && value != BackrefPropertyAccessor.UNKNOWN) {
        hydratedState[i] = types[i].resolve(value, session, entity);
      }
    }

    // Must occur after resolving identifiers!
    if (session.isEventSource()) {
      preLoadEvent.setEntity(entity).setState(hydratedState).setId(id).setPersister(persister);
      PreLoadEventListener[] listeners = session.getListeners().getPreLoadEventListeners();
      for (int i = 0; i < listeners.length; i++) {
        listeners[i].onPreLoad(preLoadEvent);
      }
    }

    persister.setPropertyValues(entity, hydratedState, session.getEntityMode());

    final SessionFactoryImplementor factory = session.getFactory();
    if (persister.hasCache() && session.getCacheMode().isPutEnabled()) {

      if (log.isDebugEnabled())
        log.debug(
            "adding entity to second-level cache: "
                + MessageHelper.infoString(persister, id, session.getFactory()));

      Object version = Versioning.getVersion(hydratedState, persister);
      CacheEntry entry =
          new CacheEntry(
              hydratedState,
              persister,
              entityEntry.isLoadedWithLazyPropertiesUnfetched(),
              version,
              session,
              entity);
      CacheKey cacheKey =
          new CacheKey(
              id,
              persister.getIdentifierType(),
              persister.getRootEntityName(),
              session.getEntityMode(),
              session.getFactory());
      boolean put =
          persister
              .getCache()
              .put(
                  cacheKey,
                  persister.getCacheEntryStructure().structure(entry),
                  session.getTimestamp(),
                  version,
                  persister.isVersioned() ? persister.getVersionType().getComparator() : null,
                  useMinimalPuts(
                      session,
                      entityEntry)); // we could use persister.hasLazyProperties() instead of true

      if (put && factory.getStatistics().isStatisticsEnabled()) {
        factory
            .getStatisticsImplementor()
            .secondLevelCachePut(persister.getCache().getRegionName());
      }
    }

    if (readOnly || !persister.isMutable()) {
      // no need to take a snapshot - this is a
      // performance optimization, but not really
      // important, except for entities with huge
      // mutable property values
      persistenceContext.setEntryStatus(entityEntry, Status.READ_ONLY);
    } else {
      // take a snapshot
      TypeFactory.deepCopy(
          hydratedState,
          persister.getPropertyTypes(),
          persister.getPropertyUpdateability(),
          hydratedState, // after setting values to object, entityMode
          session);
      persistenceContext.setEntryStatus(entityEntry, Status.MANAGED);
    }

    persister.afterInitialize(entity, entityEntry.isLoadedWithLazyPropertiesUnfetched(), session);

    if (session.isEventSource()) {
      postLoadEvent.setEntity(entity).setId(id).setPersister(persister);
      PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
      for (int i = 0; i < listeners.length; i++) {
        listeners[i].onPostLoad(postLoadEvent);
      }
    }

    if (log.isDebugEnabled())
      log.debug(
          "done materializing entity "
              + MessageHelper.infoString(persister, id, session.getFactory()));

    if (factory.getStatistics().isStatisticsEnabled()) {
      factory.getStatisticsImplementor().loadEntity(persister.getEntityName());
    }
  }
  /**
   * Handle the given delete event. This is the cascaded form.
   *
   * @param event The delete event.
   * @param transientEntities The cache of entities already deleted
   * @throws HibernateException
   */
  public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {

    final EventSource source = event.getSession();

    final PersistenceContext persistenceContext = source.getPersistenceContext();
    Object entity = persistenceContext.unproxyAndReassociate(event.getObject());

    EntityEntry entityEntry = persistenceContext.getEntry(entity);
    final EntityPersister persister;
    final Serializable id;
    final Object version;

    if (entityEntry == null) {
      LOG.trace("Entity was not persistent in delete processing");

      persister = source.getEntityPersister(event.getEntityName(), entity);

      if (ForeignKeys.isTransient(persister.getEntityName(), entity, null, source)) {
        deleteTransientEntity(
            source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities);
        // EARLY EXIT!!!
        return;
      }
      performDetachedEntityDeletionCheck(event);

      id = persister.getIdentifier(entity, source);

      if (id == null) {
        throw new TransientObjectException(
            "the detached instance passed to delete() had a null identifier");
      }

      final EntityKey key = source.generateEntityKey(id, persister);

      persistenceContext.checkUniqueness(key, entity);

      new OnUpdateVisitor(source, id, entity).process(entity, persister);

      version = persister.getVersion(entity);

      entityEntry =
          persistenceContext.addEntity(
              entity,
              (persister.isMutable() ? Status.MANAGED : Status.READ_ONLY),
              persister.getPropertyValues(entity),
              key,
              version,
              LockMode.NONE,
              true,
              persister,
              false);
    } else {
      LOG.trace("Deleting a persistent instance");

      if (entityEntry.getStatus() == Status.DELETED || entityEntry.getStatus() == Status.GONE) {
        LOG.trace("Object was already deleted");
        return;
      }
      persister = entityEntry.getPersister();
      id = entityEntry.getId();
      version = entityEntry.getVersion();
    }

    /*if ( !persister.isMutable() ) {
    	throw new HibernateException(
    			"attempted to delete an object of immutable class: " +
    			MessageHelper.infoString(persister)
    		);
    }*/

    if (invokeDeleteLifecycle(source, entity, persister)) {
      return;
    }

    deleteEntity(
        source,
        entity,
        entityEntry,
        event.isCascadeDeleteEnabled(),
        event.isOrphanRemovalBeforeUpdates(),
        persister,
        transientEntities);

    if (source.getFactory().getSettings().isIdentifierRollbackEnabled()) {
      persister.resetIdentifier(entity, id, version, source);
    }
  }