Skip to content

Commit 4a13699

Browse files
Merge pull request darrachequesne#16 from darrachequesne/patch-3
Ensure related entities are eagerly loaded
2 parents 6a09077 + 05f6d3e commit 4a13699

File tree

5 files changed

+56
-2
lines changed

5 files changed

+56
-2
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
<spring.version>4.2.0.RELEASE</spring.version>
6666
<spring.data.jpa.version>1.8.2.RELEASE</spring.data.jpa.version>
67-
<hibernate.version>4.3.10.Final</hibernate.version>
67+
<hibernate.version>4.3.11.Final</hibernate.version>
6868
<hibernate.validator.version>5.2.0.Final</hibernate.validator.version>
6969
<jackson.version>2.6.0</jackson.version>
7070
<javax.el.api.version>2.2.5</javax.el.api.version>

src/main/java/org/springframework/data/jpa/datatables/repository/DataTablesUtils.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import javax.persistence.criteria.CriteriaBuilder;
88
import javax.persistence.criteria.CriteriaQuery;
99
import javax.persistence.criteria.Expression;
10+
import javax.persistence.criteria.Fetch;
1011
import javax.persistence.criteria.From;
1112
import javax.persistence.criteria.JoinType;
1213
import javax.persistence.criteria.Predicate;
@@ -102,6 +103,29 @@ public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
102103
}
103104
predicate = criteriaBuilder.and(predicate, matchOneColumnPredicate);
104105
}
106+
// findAll method does a count query first, and then query for the actual data. Yet in the
107+
// count query, adding a JOIN FETCH results in the following error 'query specified join
108+
// fetching, but the owner of the fetched association was not present in the select list'
109+
// see https://jira.spring.io/browse/DATAJPA-105
110+
boolean isCountQuery = query.getResultType() == Long.class;
111+
if (isCountQuery) {
112+
return predicate;
113+
}
114+
// add JOIN FETCH when necessary
115+
for (ColumnParameter column : input.getColumns()) {
116+
if (!column.getSearchable() || !column.getData().contains(ATTRIBUTE_SEPARATOR)) {
117+
continue;
118+
}
119+
String[] values = column.getData().split("\\" + ATTRIBUTE_SEPARATOR);
120+
if (root.getModel().getAttribute(values[0])
121+
.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) {
122+
continue;
123+
}
124+
Fetch<?, ?> fetch = null;
125+
for (int i = 0; i < values.length - 1; i++) {
126+
fetch = (fetch == null ? root : fetch).fetch(values[i], JoinType.LEFT);
127+
}
128+
}
105129
return predicate;
106130
}
107131

src/test/java/org/springframework/data/jpa/datatables/Config.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import javax.sql.DataSource;
77

8+
import org.hibernate.SessionFactory;
89
import org.hibernate.cfg.Environment;
10+
import org.hibernate.jpa.HibernateEntityManagerFactory;
911
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
1012
import org.springframework.context.annotation.Bean;
1113
import org.springframework.context.annotation.Configuration;
@@ -60,4 +62,10 @@ public AbstractEntityManagerFactoryBean entityManagerFactory() throws SQLExcepti
6062

6163
return bean;
6264
}
65+
66+
@Bean
67+
public SessionFactory sessionFactory() throws SQLException {
68+
return ((HibernateEntityManagerFactory) entityManagerFactory().getObject()).getSessionFactory();
69+
}
70+
6371
}

src/test/java/org/springframework/data/jpa/datatables/repository/LessonRepositoryTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import static org.junit.Assert.assertNotNull;
55
import static org.junit.Assert.assertNull;
66

7+
import org.hibernate.SessionFactory;
8+
import org.hibernate.stat.Statistics;
79
import org.junit.Test;
810
import org.junit.runner.RunWith;
911
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +24,9 @@ public class LessonRepositoryTest {
2224
@Autowired
2325
private LessonRepository lessonRepository;
2426

27+
@Autowired
28+
private SessionFactory sessionFactory;
29+
2530
@Test
2631
public void testThroughTwoManyToOneRelationships() {
2732
DataTablesInput input = getBasicInput();
@@ -41,6 +46,22 @@ public void testThroughTwoManyToOneRelationships() {
4146
assertEquals(7, output.getRecordsTotal());
4247
}
4348

49+
@Test
50+
public void testEagerLoading() {
51+
DataTablesInput input = getBasicInput();
52+
53+
Statistics statistics = sessionFactory.getStatistics();
54+
statistics.setStatisticsEnabled(true);
55+
DataTablesOutput<Lesson> output = lessonRepository.findAll(input);
56+
assertEquals("CourseTypeA", output.getData().get(0).getCourse().getType().getName());
57+
statistics.setStatisticsEnabled(false);
58+
59+
// there should be only three executed queries : count unfiltered, count filtered and actual
60+
// data (with FETCH JOIN)
61+
assertEquals(3, statistics.getPrepareStatementCount());
62+
assertEquals(7 + 3 + 2, statistics.getEntityLoadCount());
63+
}
64+
4465
/**
4566
*
4667
* @return basic input parameters

src/test/resources/log4j.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ log4j.appender.console.layout=org.apache.log4j.PatternLayout
44
log4j.appender.console.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
55
log4j.appender.console=org.apache.log4j.ConsoleAppender
66

7-
log4j.logger.org.springframework=INFO
7+
log4j.logger.org.springframework=INFO
8+
log4j.logger.org.hibernate.SQL=DEBUG

0 commit comments

Comments
 (0)