⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 defaultflushentityeventlistener.java

📁 hibernate-3.1.3-all-src.zip 面向对象的访问数据库工具
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
//$Id: DefaultFlushEntityEventListener.java 8751 2005-12-05 18:45:52Z steveebersole $
package org.hibernate.event.def;

import java.io.Serializable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.action.EntityUpdateAction;
import org.hibernate.classic.Validatable;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.Nullability;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status;
import org.hibernate.engine.Versioning;
import org.hibernate.event.EventSource;
import org.hibernate.event.FlushEntityEvent;
import org.hibernate.event.FlushEntityEventListener;
import org.hibernate.intercept.FieldInterceptor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import org.hibernate.util.ArrayHelper;

/**
 * An event that occurs for each entity instance at flush time
 * 
 * @author Gavin King
 */
public class DefaultFlushEntityEventListener implements FlushEntityEventListener {
	
	private static final Log log = LogFactory.getLog(DefaultFlushEntityEventListener.class);

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

		if ( persister.hasIdentifierPropertyOrEmbeddedCompositeIdentifier() ) {

			Serializable oid = persister.getIdentifier( object, entityMode );
			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) ) {
				throw new HibernateException(
						"identifier of an instance of " +
						persister.getEntityName() +
						" was altered from " + id +
						" to " + oid
					);
			}
		}

	}
	
	private void checkNaturalId(
			EntityPersister persister,
	        Serializable identifier,
	        Object[] current,
	        Object[] loaded,
	        EntityMode entityMode,
	        SessionImplementor session) {
		if ( persister.hasNaturalIdentifier() ) {
			if ( loaded == null ) {
				loaded = session.getPersistenceContext().getNaturalIdSnapshot( identifier, persister );
			}
			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] ) {
					if ( !types[prop].isEqual( current[prop], loaded[prop], entityMode ) ) {
						throw new HibernateException(
								"immutable natural identifier of an instance of " +
								persister.getEntityName() +
								" was altered"
							);
					}
				}
			}
		}
	}

	/**
	 * Flushes a single entity's state to the database, by scheduling
	 * an update action, if necessary
	 */
	public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
		final Object entity = event.getEntity();
		final EntityEntry entry = event.getEntityEntry();
		final EventSource session = event.getSession();
		final EntityPersister persister = entry.getPersister();
		final Status status = entry.getStatus();
		final EntityMode entityMode = session.getEntityMode();
		final Type[] types = persister.getPropertyTypes();
		
		final boolean mightBeDirty = entry.requiresDirtyCheck(entity);

		final Object[] values = getValues( entity, entry, entityMode, mightBeDirty, session );
		
		event.setPropertyValues(values);

		//TODO: avoid this for non-new instances where mightBeDirty==false
		boolean substitute = wrapCollections( session, persister, types, values);
		
		if ( isUpdateNecessary( event, mightBeDirty ) ) {
			substitute = scheduleUpdate( event ) || substitute;
		}

		if ( status != Status.DELETED ) {
			// now update the object .. has to be outside the main if block above (because of collections)
			if (substitute) persister.setPropertyValues( entity, values, entityMode );

			// Search for collections by reachability, updating their role.
			// We don't want to touch collections reachable from a deleted object
			if ( persister.hasCollections() ) {
				new FlushVisitor(session, entity).processEntityPropertyValues(values, types);
			}
		}

	}

	private Object[] getValues(
			Object entity, 
			EntityEntry entry,  
			EntityMode entityMode, 
			boolean mightBeDirty,
	        SessionImplementor session
	) {
		final Object[] loadedState = entry.getLoadedState();
		final Status status = entry.getStatus();
		final EntityPersister persister = entry.getPersister();
		
		final Object[] values;
		if ( status == Status.DELETED ) {
			//grab its state saved at deletion
			values = entry.getDeletedState();
		}
		else if ( !mightBeDirty && loadedState!=null ) {
			values = loadedState;
		}
		else {
			checkId( entity, persister, entry.getId(), entityMode );
			
			// grab its current state
			values = persister.getPropertyValues( entity, entityMode );
			
			checkNaturalId( persister, entry.getId(), values, loadedState, entityMode, session );
		}
		return values;
	}

	private boolean wrapCollections(
			EventSource session, 
			EntityPersister persister, 
			Type[] types, 
			Object[] values
	) {
		if ( persister.hasCollections() ) {

			// wrap up any new collections directly referenced by the object
			// or its components

			// NOTE: we need to do the wrap here even if its not "dirty",
			// because collections need wrapping but changes to _them_
			// don't dirty the container. Also, for versioned data, we
			// need to wrap before calling searchForDirtyCollections

			WrapVisitor visitor = new WrapVisitor(session);
			// substitutes into values by side-effect
			visitor.processEntityPropertyValues(values, types);
			return visitor.isSubstitutionRequired();
		}
		else {
			return false;
		}
	}

	private boolean isUpdateNecessary(final FlushEntityEvent event, final boolean mightBeDirty) {
		final Status status = event.getEntityEntry().getStatus();
		if ( mightBeDirty || status==Status.DELETED ) {
			// compare to cached state (ignoring collections unless versioned)
			dirtyCheck(event);
			if ( isUpdateNecessary(event) ) {
				return true;
			}
			else {
				FieldInterceptor.clearDirty( event.getEntity() );
				return false;
			}
		}
		else {
			return hasDirtyCollections( event, event.getEntityEntry().getPersister(), status );
		}
	}

	private boolean scheduleUpdate(final FlushEntityEvent event) {
		
		final EntityEntry entry = event.getEntityEntry();
		final EventSource session = event.getSession();
		final Object entity = event.getEntity();
		final Status status = entry.getStatus();
		final EntityMode entityMode = session.getEntityMode();
		final EntityPersister persister = entry.getPersister();
		final Object[] values = event.getPropertyValues();
		
		if ( log.isTraceEnabled() ) {
			if ( status == Status.DELETED ) {
				log.trace(
						"Updating deleted entity: " +
						MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
					);
			}
			else {
				log.trace(
						"Updating entity: " +
						MessageHelper.infoString( persister, entry.getId(), session.getFactory()  )
					);
			}
		}
		
		boolean substitute;
		
		if ( !entry.isBeingReplicated() ) {
			// give the Interceptor a chance to process property values, if the properties 
			// were modified by the Interceptor, we need to set them back to the object
			substitute = handleInterception(event);
		}
		else {
			substitute = false;
		}

		validate( entity, persister, status, entityMode );

		// increment the version number (if necessary)
		final Object nextVersion = getNextVersion(event);

		// if it was dirtied by a collection only
		int[] dirtyProperties = event.getDirtyProperties();
		if ( event.isDirtyCheckPossible() && dirtyProperties==null ) {
			if ( !event.hasDirtyCollection() ) {
				throw new AssertionFailure("dirty, but no dirty properties");
			}
			dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
		}

		// check nullability but do not perform command execute
		// we'll use scheduled updates for that.
		new Nullability(session).checkNullability( values, persister, true );

		// schedule the update
		// note that we intentionally do _not_ pass in currentPersistentState!

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -