HHH-11076 - Lazy collections ignore filters when allowLoadOutsideTransaction is true

This commit is contained in:
Giovanni Lovato 2016-09-01 14:51:57 +02:00 committed by Vlad Mihalcea
parent 87e69c9d34
commit ae40de125d
3 changed files with 127 additions and 3 deletions

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -17,6 +18,7 @@ import java.util.ListIterator;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
@ -73,6 +75,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
private String sessionFactoryUuid;
private boolean allowLoadOutsideTransaction;
private Map<String, Filter> enabledFilters;
/**
* Not called by Hibernate, but used by non-JDK serialization,
@ -83,6 +86,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected AbstractPersistentCollection(SharedSessionContractImplementor session) {
this.session = session;
enabledFilters = new HashMap<>( session.getLoadQueryInfluencers().getEnabledFilters() );
}
@Override
@ -218,7 +222,6 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
SharedSessionContractImplementor originalSession = null;
boolean isJTA = false;
@ -227,9 +230,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
originalSession = session;
session = tempSession;
isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
if ( !isJTA ) {
// Explicitly handle the transactions only if we're not in
// a JTA environment. A lazy loading temporary session can
@ -277,6 +279,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
final SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();
session.getPersistenceContext().setDefaultReadOnly( true );
session.setFlushMode( FlushMode.MANUAL );
session.getLoadQueryInfluencers().getEnabledFilters().putAll( enabledFilters );
return session;
}

View File

@ -0,0 +1,47 @@
/*
* 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.jpa.test.hibernateFilters;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import org.hibernate.annotations.Filter;
/**
* @author Vlad Mihalcea
*/
@Entity
public class AccountGroup {
@Id
private Long id;
@OneToMany
@JoinColumn(name = "group_id")
@Filter( name = "byRegion", condition = "region_cd = :region" )
private List<Account> accounts = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.jpa.test.hibernateFilters;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
public class ProxyPreservingFiltersOutsideInitialSessionTest
extends BaseEntityManagerFunctionalTestCase {
@Override
public Class[] getAnnotatedClasses() {
return new Class[] {
AccountGroup.class,
Account.class
};
}
@Override
protected Map buildSettings() {
Map settings = super.buildSettings();
settings.put( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
return settings;
}
@Test
public void testPreserveFilters() {
doInJPA( this::entityManagerFactory, entityManager -> {
AccountGroup accountGroup = new AccountGroup();
accountGroup.setId( 1L );
entityManager.persist( accountGroup );
Account account = new Account();
account.setName( "A1" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A2" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A3" );
account.setRegionCode( "US" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
} );
AccountGroup group = doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "US" );
return entityManager.find( AccountGroup.class, 1L );
} );
assertEquals(1, group.getAccounts().size());
}
}