defaultmergeeventlistener.java
来自「hibernate-distribution-3.3.1.GA-dist.zip」· Java 代码 · 共 491 行 · 第 1/2 页
JAVA
491 行
/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA * */package org.hibernate.event.def;import java.io.Serializable;import java.util.Iterator;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.AssertionFailure;import org.hibernate.HibernateException;import org.hibernate.ObjectDeletedException;import org.hibernate.StaleObjectStateException;import org.hibernate.TransientObjectException;import org.hibernate.WrongClassException;import org.hibernate.engine.Cascade;import org.hibernate.engine.CascadingAction;import org.hibernate.engine.EntityEntry;import org.hibernate.engine.EntityKey;import org.hibernate.engine.SessionImplementor;import org.hibernate.engine.Status;import org.hibernate.event.EventSource;import org.hibernate.event.MergeEvent;import org.hibernate.event.MergeEventListener;import org.hibernate.intercept.FieldInterceptionHelper;import org.hibernate.intercept.FieldInterceptor;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.proxy.HibernateProxy;import org.hibernate.proxy.LazyInitializer;import org.hibernate.type.ForeignKeyDirection;import org.hibernate.type.TypeFactory;import org.hibernate.util.IdentityMap;/** * Defines the default copy event listener used by hibernate for copying entities * in response to generated copy events. * * @author Gavin King */public class DefaultMergeEventListener extends AbstractSaveEventListener implements MergeEventListener { private static final Logger log = LoggerFactory.getLogger(DefaultMergeEventListener.class); protected Map getMergeMap(Object anything) { return IdentityMap.invert( (Map) anything ); } /** * Handle the given merge event. * * @param event The merge event to be handled. * @throws HibernateException */ public void onMerge(MergeEvent event) throws HibernateException { Map copyCache = IdentityMap.instantiate(10); onMerge( event, copyCache ); for ( Iterator it=copyCache.values().iterator(); it.hasNext(); ) { Object entity = it.next(); if ( entity instanceof HibernateProxy ) { entity = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getImplementation(); } EntityEntry entry = event.getSession().getPersistenceContext().getEntry( entity ); if ( entry == null ) { throw new TransientObjectException( "object references an unsaved transient instance - save the transient instance before merging: " + event.getSession().guessEntityName( entity ) ); // TODO: cache the entity name somewhere so that it is available to this exception // entity name will not be available for non-POJO entities } if ( entry.getStatus() != Status.MANAGED ) { throw new AssertionFailure( "Merged entity does not have status set to MANAGED; "+entry+" status="+entry.getStatus() ); } } } /** * Handle the given merge event. * * @param event The merge event to be handled. * @throws HibernateException */ public void onMerge(MergeEvent event, Map copyCache) throws HibernateException { final EventSource source = event.getSession(); final Object original = event.getOriginal(); if ( original != null ) { final Object entity; if ( original instanceof HibernateProxy ) { LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer(); if ( li.isUninitialized() ) { log.trace("ignoring uninitialized proxy"); event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) ); return; //EARLY EXIT! } else { entity = li.getImplementation(); } } else { entity = original; } if ( copyCache.containsKey(entity) && source.getContextEntityIdentifier( copyCache.get( entity ) ) != null ) { log.trace("already merged"); event.setResult(entity); } else { event.setEntity( entity ); int entityState = -1; // Check the persistence context for an entry relating to this // entity to be merged... EntityEntry entry = source.getPersistenceContext().getEntry( entity ); if ( entry == null ) { EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); Serializable id = persister.getIdentifier( entity, source.getEntityMode() ); if ( id != null ) { EntityKey key = new EntityKey( id, persister, source.getEntityMode() ); Object managedEntity = source.getPersistenceContext().getEntity( key ); entry = source.getPersistenceContext().getEntry( managedEntity ); if ( entry != null ) { // we have specialized case of a detached entity from the // perspective of the merge operation. Specifically, we // have an incoming entity instance which has a corresponding // entry in the current persistence context, but registered // under a different entity instance entityState = DETACHED; } } } if ( entityState == -1 ) { entityState = getEntityState( entity, event.getEntityName(), entry, source ); } switch (entityState) { case DETACHED: entityIsDetached(event, copyCache); break; case TRANSIENT: entityIsTransient(event, copyCache); break; case PERSISTENT: entityIsPersistent(event, copyCache); break; default: //DELETED throw new ObjectDeletedException( "deleted instance passed to merge", null, getLoggableName( event.getEntityName(), entity ) ); } } } } protected void entityIsPersistent(MergeEvent event, Map copyCache) { log.trace("ignoring persistent instance"); //TODO: check that entry.getIdentifier().equals(requestedId) final Object entity = event.getEntity(); final EventSource source = event.getSession(); final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); copyCache.put(entity, entity); //before cascade! cascadeOnMerge(source, persister, entity, copyCache); copyValues(persister, entity, entity, source, copyCache); event.setResult(entity); } protected void entityIsTransient(MergeEvent event, Map copyCache) { log.trace("merging transient instance"); final Object entity = event.getEntity(); final EventSource source = event.getSession(); final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); final String entityName = persister.getEntityName(); final Serializable id = persister.hasIdentifierProperty() ? persister.getIdentifier( entity, source.getEntityMode() ) : null; if ( copyCache.containsKey( entity ) ) { persister.setIdentifier( copyCache.get( entity ), id, source.getEntityMode() ); } else { copyCache.put(entity, persister.instantiate( id, source.getEntityMode() ) ); //before cascade! //TODO: should this be Session.instantiate(Persister, ...)? } final Object copy = copyCache.get( entity ); // cascade first, so that all unsaved objects get their // copy created before we actually copy //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE); super.cascadeBeforeSave(source, persister, entity, copyCache); copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT); //this bit is only *really* absolutely necessary for handling //requestedId, but is also good if we merge multiple object //graphs, since it helps ensure uniqueness final Serializable requestedId = event.getRequestedId(); if (requestedId==null) { saveWithGeneratedId( copy, entityName, copyCache, source, false ); } else { saveWithRequestedId( copy, requestedId, entityName, copyCache, source ); } // cascade first, so that all unsaved objects get their // copy created before we actually copy super.cascadeAfterSave(source, persister, entity, copyCache);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?