HHH-12260: refactor org.hibernate.event.internal.EvictVisitor#evictCollection
This commit is contained in:
parent
f1a31b61d2
commit
39760a7788
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue