Skip to content

Commit b51a61c

Browse files
Merge pull request #14 from darrachequesne/patch-1
Add support for nested @manytoone relationships
2 parents 36db5ea + 5ba97e9 commit b51a61c

File tree

9 files changed

+247
-3
lines changed

9 files changed

+247
-3
lines changed

pom.xml

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

66
<groupId>com.github.darrachequesne</groupId>
77
<artifactId>spring-data-jpa-datatables</artifactId>
8-
<version>2.2</version>
8+
<version>2.3-SNAPSHOT</version>
99

1010
<name>Spring Data JPA for DataTables</name>
1111
<description>Spring Data JPA extension to work with the great jQuery plug-in DataTables (http://datatables.net/)</description>

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
import javax.persistence.criteria.CriteriaBuilder;
88
import javax.persistence.criteria.CriteriaQuery;
99
import javax.persistence.criteria.Expression;
10+
import javax.persistence.criteria.From;
1011
import javax.persistence.criteria.JoinType;
1112
import javax.persistence.criteria.Predicate;
1213
import javax.persistence.criteria.Root;
14+
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
1315

1416
import org.springframework.data.domain.PageRequest;
1517
import org.springframework.data.domain.Pageable;
@@ -193,10 +195,16 @@ private static Expression<String> getExpression(Root<?> root, String columnData)
193195
if (columnData.contains(ATTRIBUTE_SEPARATOR)) {
194196
// columnData is like "joinedEntity.attribute" so add a join clause
195197
String[] values = columnData.split("\\" + ATTRIBUTE_SEPARATOR);
196-
if (!root.getModel().getAttribute(values[0]).isAssociation()) {
198+
if (root.getModel().getAttribute(values[0])
199+
.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) {
200+
// with @Embedded attribute
197201
return root.get(values[0]).get(values[1]).as(String.class);
198202
}
199-
return root.join(values[0], JoinType.LEFT).get(values[1]).as(String.class);
203+
From<?, ?> from = root;
204+
for (int i = 0; i < values.length - 1; i++) {
205+
from = from.join(values[i], JoinType.LEFT);
206+
}
207+
return from.get(values[values.length - 1]).as(String.class);
200208
} else {
201209
// columnData is like "attribute" so nothing particular to do
202210
return root.get(columnData).as(String.class);

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package org.springframework.data.jpa.datatables;
22

33
import java.sql.SQLException;
4+
import java.util.Properties;
45

56
import javax.sql.DataSource;
67

8+
import org.hibernate.cfg.Environment;
9+
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
710
import org.springframework.context.annotation.Bean;
811
import org.springframework.context.annotation.Configuration;
912
import org.springframework.data.jpa.datatables.repository.DataTablesRepositoryFactoryBean;
@@ -48,6 +51,13 @@ public AbstractEntityManagerFactoryBean entityManagerFactory() throws SQLExcepti
4851
bean.setPackagesToScan(Config.class.getPackage().getName());
4952
bean.setDataSource(dataSource());
5053

54+
Properties jpaProperties = new Properties();
55+
jpaProperties.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
56+
jpaProperties.setProperty(Environment.HBM2DDL_IMPORT_FILES, "init.sql");
57+
jpaProperties.setProperty(Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR,
58+
MultipleLinesSqlCommandExtractor.class.getName());
59+
bean.setJpaProperties(jpaProperties);
60+
5161
return bean;
5262
}
5363
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.springframework.data.jpa.datatables.model;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.FetchType;
5+
import javax.persistence.GeneratedValue;
6+
import javax.persistence.Id;
7+
import javax.persistence.JoinColumn;
8+
import javax.persistence.ManyToOne;
9+
import javax.persistence.Table;
10+
11+
@Entity
12+
@Table(name = "course")
13+
public class Course {
14+
15+
@Id
16+
@GeneratedValue
17+
private Long id;
18+
19+
private String name;
20+
21+
@ManyToOne(fetch = FetchType.EAGER)
22+
@JoinColumn(name = "course_type_id")
23+
private CourseType type;
24+
25+
public Course() {}
26+
27+
public Long getId() {
28+
return id;
29+
}
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public void setName(String name) {
36+
this.name = name;
37+
}
38+
39+
public CourseType getType() {
40+
return type;
41+
}
42+
43+
public void setType(CourseType type) {
44+
this.type = type;
45+
}
46+
47+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.springframework.data.jpa.datatables.model;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.Id;
6+
import javax.persistence.Table;
7+
8+
@Entity
9+
@Table(name = "course_type")
10+
public class CourseType {
11+
12+
@Id
13+
@GeneratedValue
14+
private Long id;
15+
16+
private String name;
17+
18+
public CourseType() {}
19+
20+
public Long getId() {
21+
return id;
22+
}
23+
24+
public String getName() {
25+
return name;
26+
}
27+
28+
public void setName(String name) {
29+
this.name = name;
30+
}
31+
32+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.springframework.data.jpa.datatables.model;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.FetchType;
5+
import javax.persistence.GeneratedValue;
6+
import javax.persistence.Id;
7+
import javax.persistence.JoinColumn;
8+
import javax.persistence.ManyToOne;
9+
import javax.persistence.Table;
10+
11+
@Entity
12+
@Table(name = "lesson")
13+
public class Lesson {
14+
15+
@Id
16+
@GeneratedValue
17+
private Long id;
18+
19+
private String name;
20+
21+
@ManyToOne(fetch = FetchType.EAGER)
22+
@JoinColumn(name = "course_id")
23+
private Course course;
24+
25+
public Lesson() {}
26+
27+
public Long getId() {
28+
return id;
29+
}
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public void setName(String name) {
36+
this.name = name;
37+
}
38+
39+
public Course getCourse() {
40+
return course;
41+
}
42+
43+
public void setCourse(Course course) {
44+
this.course = course;
45+
}
46+
47+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.springframework.data.jpa.datatables.model;
2+
3+
import org.springframework.data.jpa.datatables.repository.DataTablesRepository;
4+
5+
public interface LessonRepository extends DataTablesRepository<Lesson, Long> {
6+
7+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.springframework.data.jpa.datatables.repository;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertNotNull;
5+
import static org.junit.Assert.assertNull;
6+
7+
import java.util.ArrayList;
8+
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.data.jpa.datatables.Config;
13+
import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
14+
import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;
15+
import org.springframework.data.jpa.datatables.model.Lesson;
16+
import org.springframework.data.jpa.datatables.model.LessonRepository;
17+
import org.springframework.data.jpa.datatables.parameter.ColumnParameter;
18+
import org.springframework.data.jpa.datatables.parameter.OrderParameter;
19+
import org.springframework.data.jpa.datatables.parameter.SearchParameter;
20+
import org.springframework.test.context.ContextConfiguration;
21+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
22+
23+
@RunWith(SpringJUnit4ClassRunner.class)
24+
@ContextConfiguration(classes = Config.class)
25+
public class LessonRepositoryTest {
26+
27+
@Autowired
28+
private LessonRepository lessonRepository;
29+
30+
@Test
31+
public void testThroughTwoManyToOneRelationships() {
32+
DataTablesInput input = getBasicInput();
33+
34+
input.getColumns().get(3).getSearch().setValue("CourseTypeA");
35+
DataTablesOutput<Lesson> output = lessonRepository.findAll(input);
36+
assertNotNull(output);
37+
assertNull(output.getError());
38+
assertEquals(5, (long) output.getRecordsFiltered());
39+
assertEquals(7, (long) output.getRecordsTotal());
40+
41+
input.getColumns().get(2).getSearch().setValue("CourseA-2");
42+
output = lessonRepository.findAll(input);
43+
assertNotNull(output);
44+
assertNull(output.getError());
45+
assertEquals(2, (long) output.getRecordsFiltered());
46+
assertEquals(7, (long) output.getRecordsTotal());
47+
}
48+
49+
/**
50+
*
51+
* @return basic input parameters
52+
*/
53+
private static DataTablesInput getBasicInput() {
54+
DataTablesInput input = new DataTablesInput();
55+
input.setDraw(1);
56+
input.setStart(0);
57+
input.setLength(10);
58+
input.setSearch(new SearchParameter("", false));
59+
input.setOrder(new ArrayList<OrderParameter>());
60+
input.getOrder().add(new OrderParameter(0, "asc"));
61+
62+
input.setColumns(new ArrayList<ColumnParameter>());
63+
input.getColumns()
64+
.add(new ColumnParameter("id", "", true, true, new SearchParameter("", false)));
65+
input.getColumns()
66+
.add(new ColumnParameter("name", "", true, true, new SearchParameter("", false)));
67+
input.getColumns()
68+
.add(new ColumnParameter("course.name", "", true, true, new SearchParameter("", false)));
69+
input.getColumns().add(
70+
new ColumnParameter("course.type.name", "", true, true, new SearchParameter("", false)));
71+
72+
return input;
73+
}
74+
}

src/test/resources/init.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
INSERT INTO course_type (id, name) VALUES
2+
(1, 'CourseTypeA'),
3+
(2, 'CourseTypeB'),
4+
(3, 'CourseTypeC');
5+
6+
INSERT INTO course (id, name, course_type_id) VALUES
7+
(1, 'CourseA-1', 1),
8+
(2, 'CourseA-2', 1),
9+
(3, 'CourseA-3', 1),
10+
(4, 'CourseB-1', 2);
11+
12+
INSERT INTO lesson (id, name, course_id) VALUES
13+
(1, 'LessonA-1-a', 1),
14+
(2, 'LessonA-1-b', 1),
15+
(3, 'LessonA-1-c', 1),
16+
(4, 'LessonA-2-a', 2),
17+
(5, 'LessonA-2-b', 2),
18+
(6, 'LessonB-1-a', 4),
19+
(7, 'LessonB-1-b', 4);

0 commit comments

Comments
 (0)