HHH-12260: refactor org.hibernate.event.internal.EvictVisitor#evictCollection

This commit is contained in:
Jonathan Bregler 2018-01-30 14:57:47 +01:00 committed by Vlad Mihalcea
parent f972bc017f
commit 684cfe6383
4 changed files with 166 additions and 10 deletions

View File

@ -73,9 +73,8 @@ public class DefaultEvictEventListener implements EvictEventListener {
li.unsetSession();
}
else {
EntityEntry e = persistenceContext.removeEntry( object );
EntityEntry e = persistenceContext.getEntry( object );
if ( e != null ) {
persistenceContext.removeEntity( e.getEntityKey() );
doEvict( object, e.getEntityKey(), e.getPersister(), source );
}
else {
@ -119,7 +118,7 @@ public class DefaultEvictEventListener implements EvictEventListener {
// remove all collections for the entity from the session-level cache
if ( persister.hasCollections() ) {
new EvictVisitor( session ).process( object, persister );
new EvictVisitor( session, object ).process( object, persister );
}
// remove any snapshot, not really for memory management purposes, but
@ -127,6 +126,9 @@ public class DefaultEvictEventListener implements EvictEventListener {
// EntityEntry to take precedence
// This is now handled by removeEntity()
//session.getPersistenceContext().removeDatabaseSnapshot(key);
session.getPersistenceContext().removeEntity( key );
session.getPersistenceContext().removeEntry( object );
Cascade.cascade( CascadingActions.EVICT, CascadePoint.AFTER_EVICT, session, persister, object );
}

View File

@ -140,7 +140,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
final EntityKey key = source.generateEntityKey( id, persister );
source.getPersistenceContext().removeEntity( key );
if ( persister.hasCollections() ) {
new EvictVisitor( source ).process( object, persister );
new EvictVisitor( source, object ).process( object, persister );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.event.internal;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.CollectionKey;
@ -25,9 +26,12 @@ import org.hibernate.type.CollectionType;
*/
public class EvictVisitor extends AbstractVisitor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EvictVisitor.class );
private Object owner;
EvictVisitor(EventSource session) {
EvictVisitor(EventSource session, Object owner) {
super(session);
this.owner = owner;
}
@Override
@ -38,20 +42,23 @@ public class EvictVisitor extends AbstractVisitor {
return null;
}
public void evictCollection(Object value, CollectionType type) {
final Object pc;
final PersistentCollection collection;
if ( type.hasHolder() ) {
pc = getSession().getPersistenceContext().removeCollectionHolder(value);
collection = getSession().getPersistenceContext().removeCollectionHolder(value);
}
else if ( value instanceof PersistentCollection ) {
pc = value;
collection = (PersistentCollection) value;
}
else if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
collection = (PersistentCollection) type.resolve( value, getSession(), this.owner );
}
else {
return; //EARLY EXIT!
}
PersistentCollection collection = (PersistentCollection) pc;
if ( collection.unsetSession( getSession() ) ) {
if ( collection != null && collection.unsetSession( getSession() ) ) {
evictCollection(collection);
}
}
@ -76,4 +83,9 @@ public class EvictVisitor extends AbstractVisitor {
);
}
}
@Override
boolean includeEntityProperty(Object[] values, int i) {
return true;
}
}

View File

@ -0,0 +1,142 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.lazy;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hibernate.Hibernate.isPropertyInitialized;
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertFalse;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@TestForIssue(jiraKey = "HHH-12260")
@RunWith(BytecodeEnhancerRunner.class)
public class LazyCollectionDetachTest extends BaseCoreFunctionalTestCase {
private static final int CHILDREN_SIZE = 10;
private Long parentID;
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[]{ Parent.class, Child.class };
}
@Before
public void prepare() {
doInHibernate( this::sessionFactory, s -> {
Parent parent = new Parent();
parent.setChildren( new ArrayList<>() );
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
Child child = new Child();
child.parent = parent;
s.persist( child );
}
s.persist( parent );
parentID = parent.id;
} );
}
@Test
public void testDetach() {
doInHibernate( this::sessionFactory, s -> {
Parent parent = s.find( Parent.class, parentID );
assertThat( parent, notNullValue() );
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
assertFalse( isPropertyInitialized( parent, "children" ) );
checkDirtyTracking( parent );
s.detach( parent );
s.flush();
} );
}
@Test
public void testDetachProxy() {
doInHibernate( this::sessionFactory, s -> {
Parent parent = s.getReference( Parent.class, parentID );
checkDirtyTracking( parent );
s.detach( parent );
s.flush();
} );
}
@Test
public void testRefresh() {
doInHibernate( this::sessionFactory, s -> {
Parent parent = s.find( Parent.class, parentID );
assertThat( parent, notNullValue() );
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
assertFalse( isPropertyInitialized( parent, "children" ) );
checkDirtyTracking( parent );
s.refresh( parent );
s.flush();
} );
}
@Entity
@Table(name = "PARENT")
private static class Parent {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
List<Child> children;
void setChildren(List<Child> children) {
this.children = children;
}
}
@Entity
@Table(name = "CHILD")
private static class Child {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Parent parent;
Child() {
}
}
}