Skip to content

Commit

Permalink
HHH-10679 : Add TRACE logging and another test
Browse files Browse the repository at this point in the history
  • Loading branch information
gbadner committed Apr 29, 2016
1 parent 229d2e9 commit ca159c5
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 1 deletion.
28 changes: 27 additions & 1 deletion hibernate-core/src/main/java/org/hibernate/loader/Loader.java
Expand Up @@ -1005,7 +1005,13 @@ private static Set[] transpose( List keys ) {
}

private void createSubselects(List keys, QueryParameters queryParameters, SessionImplementor session) {
if ( keys.size() > 1 ) { //if we only returned one entity, query by key is more efficient
if ( keys.size() < 2 ) {
LOG.tracef(
"Loader [%s] Skipping subselect because there are fewer than 2 results, so query by key is more efficient.",
getClass().getName()
);
}
else {

Set[] keySets = transpose(keys);

Expand All @@ -1017,6 +1023,17 @@ private void createSubselects(List keys, QueryParameters queryParameters, Sessio
queryParameters
);
final Iterator iter = keys.iterator();

if ( LOG.isTraceEnabled() && loadables.length > 1 ) {
LOG.tracef(
"Loader [%s] : persisters [%s], aliases [%s], query [%s]",
getClass().getName(),
Arrays.asList( loadables ),
Arrays.asList( aliases ),
subselectQueryString
);
}

while ( iter.hasNext() ) {

final EntityKey[] rowKeys = (EntityKey[]) iter.next();
Expand All @@ -1033,6 +1050,15 @@ private void createSubselects(List keys, QueryParameters queryParameters, Sessio
namedParameterLocMap
);

LOG.tracef(
"Loader [%s] created subselect: persister [%s], alias [%s], query [%s], entityKeys [%s]",
getClass().getName(),
loadables[i],
aliases[i],
subselectQueryString,
keySets[i]
);

session.getPersistenceContext()
.getBatchFetchQueue()
.addSubselect( rowKeys[i], subselectFetch );
Expand Down
Expand Up @@ -27,8 +27,11 @@
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

Expand All @@ -42,6 +45,7 @@
import org.hibernate.annotations.FetchMode;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

import static org.junit.Assert.assertEquals;
Expand All @@ -60,6 +64,7 @@ public void configure(Configuration cfg) {
}

@Test
@TestForIssue( jiraKey = "HHH-10679")
public void testSubselectFetchFromEntityBatch() {
Session s = openSession();
Transaction t = s.beginTransaction();
Expand Down Expand Up @@ -195,6 +200,136 @@ public void testSubselectFetchFromQueryList() {
s.close();
}

@Test
@TestForIssue( jiraKey = "HHH-10679")
public void testMultiSubselectFetchSamePersisterQueryList() {
Session s = openSession();
Transaction t = s.beginTransaction();
EmployeeGroup group1 = new EmployeeGroup();
Employee employee1 = new Employee("Jane");
Employee employee2 = new Employee("Jeff");
group1.addEmployee( employee1 );
group1.addEmployee( employee2 );
group1.setManager( new Employee( "group1 manager" ) );
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#1" ) );
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#2" ) );
group1.setLead( new Employee( "group1 lead" ) );
group1.getLead().addCollaborator( new Employee( "group1 lead's collaborator#1" ) );
EmployeeGroup group2 = new EmployeeGroup();
Employee employee3 = new Employee("Joan");
Employee employee4 = new Employee("John");
group2.addEmployee( employee3 );
group2.addEmployee( employee4 );
group2.setManager( new Employee( "group2 manager" ) );
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#1" ) );
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#2" ) );
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#3" ) );
group2.setLead( new Employee( "group2 lead" ) );
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#1" ) );
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#2" ) );
s.save( group1 );
s.save( group2 );
s.flush();

s.clear();

sessionFactory().getStatistics().clear();

EmployeeGroup[] groups = new EmployeeGroup[] {
(EmployeeGroup) s.load(EmployeeGroup.class, group1.getId()),
(EmployeeGroup) s.load(EmployeeGroup.class, group2.getId())
};

// groups should only contain proxies
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

for (EmployeeGroup group : groups) {
assertFalse( Hibernate.isInitialized( group ) );
}

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );


for (int i = 0 ; i < groups.length; i++ ) {
// Both groups get initialized and are added to the PersistenceContext when i == 0;
// Still need to call Hibernate.initialize( groups[i] ) for i > 0 so that the entity
// in the PersistenceContext gets assigned to its respective proxy target (is this a
// bug???)
Hibernate.initialize( groups[ i ] );
assertTrue( Hibernate.isInitialized( groups[i] ) );
assertTrue( Hibernate.isInitialized( groups[i].getLead() ) );
assertFalse( Hibernate.isInitialized( groups[i].getLead().getCollaborators() ) );
assertTrue( Hibernate.isInitialized( groups[i].getManager() ) );
assertFalse( Hibernate.isInitialized( groups[i].getManager().getCollaborators() ) );
// the collections should be uninitialized
assertFalse( Hibernate.isInitialized( groups[i].getEmployees() ) );
}

// both Group proxies should have been loaded in the same batch;
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
sessionFactory().getStatistics().clear();

for (EmployeeGroup group : groups) {
assertTrue( Hibernate.isInitialized( group ) );
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
}

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

// now initialize the collection in the first; collections in both groups
// should get initialized
Hibernate.initialize( groups[0].getEmployees() );

assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
sessionFactory().getStatistics().clear();

// all EmployeeGroup#employees should be initialized now
for (EmployeeGroup group : groups) {
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
assertFalse( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
}

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

// now initialize groups[0].getLead().getCollaborators();
// groups[1].getLead().getCollaborators() should also be initialized
Hibernate.initialize( groups[0].getLead().getCollaborators() );

assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
sessionFactory().getStatistics().clear();

for (EmployeeGroup group : groups) {
assertTrue( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
}

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

// now initialize groups[0].getManager().getCollaborators();
// groups[1].getManager().getCollaborators() should also be initialized
Hibernate.initialize( groups[0].getManager().getCollaborators() );

assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
sessionFactory().getStatistics().clear();

for (EmployeeGroup group : groups) {
assertTrue( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
}

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

assertEquals( group1.getLead().getCollaborators().size(), groups[0].getLead().getCollaborators().size() );
assertEquals( group2.getLead().getCollaborators().size(), groups[1].getLead().getCollaborators().size() );
assertEquals( group1.getManager().getCollaborators().size(), groups[0].getManager().getCollaborators().size() );
assertEquals( group2.getManager().getCollaborators().size(), groups[1].getManager().getCollaborators().size() );

assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );

t.rollback();
s.close();
}

public Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EmployeeGroup.class, Employee.class };
}
Expand All @@ -208,8 +343,15 @@ private static class EmployeeGroup {
@GeneratedValue
private Long id;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Employee manager;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Employee lead;

@OneToMany(cascade = CascadeType.ALL)
@Fetch(FetchMode.SUBSELECT)
@JoinTable(name="EmployeeGroup_employees")
private List<Employee> employees = new ArrayList<Employee>();

public EmployeeGroup(long id) {
Expand All @@ -220,6 +362,22 @@ public EmployeeGroup(long id) {
protected EmployeeGroup() {
}

public Employee getManager() {
return manager;
}

public void setManager(Employee manager) {
this.manager = manager;
}

public Employee getLead() {
return lead;
}

public void setLead(Employee lead) {
this.lead = lead;
}

public boolean addEmployee(Employee employee) {
return employees.add(employee);
}
Expand Down Expand Up @@ -247,6 +405,10 @@ private static class Employee {
private Long id;
private String name;

@OneToMany(cascade = CascadeType.ALL)
@Fetch(FetchMode.SUBSELECT)
private List<Employee> collaborators = new ArrayList<Employee>();

public String getName() {
return name;
}
Expand All @@ -259,6 +421,14 @@ public Employee(String name) {
this.name = name;
}

public boolean addCollaborator(Employee employee) {
return collaborators.add(employee);
}

public List<Employee> getCollaborators() {
return collaborators;
}

@Override
public String toString() {
return name;
Expand Down

0 comments on commit ca159c5

Please sign in to comment.