Skip to content

Commit

Permalink
HHH-12260: refactor org.hibernate.event.internal.EvictVisitor#evictCo…
Browse files Browse the repository at this point in the history
…llection
  • Loading branch information
breglerj authored and vladmihalcea committed Feb 21, 2018
1 parent f1a31b6 commit 39760a7
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 10 deletions.
Expand Up @@ -73,9 +73,8 @@ public void onEvict(EvictEvent event) throws HibernateException {
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 {
Expand Down Expand Up @@ -119,14 +118,17 @@ protected void doEvict(

// 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
// rather because it might now be stale, and there is no longer any
// 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 );
}
Expand Down
Expand Up @@ -140,7 +140,7 @@ public void onRefresh(RefreshEvent event, Map refreshedAlready) {
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 );
}
}

Expand Down
Expand Up @@ -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;
Expand All @@ -25,9 +26,12 @@
*/
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
Expand All @@ -38,20 +42,23 @@ Object processCollection(Object collection, CollectionType type) throws Hibernat

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);
}
}
Expand All @@ -76,4 +83,9 @@ private void evictCollection(PersistentCollection collection) {
);
}
}

@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() {
}
}
}

0 comments on commit 39760a7

Please sign in to comment.