diff --git a/pom.xml b/pom.xml
index 0709742..c652f36 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.github.darrachequesne
spring-data-jpa-datatables
- 2.2
+ 2.3-SNAPSHOT
Spring Data JPA for DataTables
Spring Data JPA extension to work with the great jQuery plug-in DataTables (http://datatables.net/)
diff --git a/src/main/java/org/springframework/data/jpa/datatables/repository/DataTablesUtils.java b/src/main/java/org/springframework/data/jpa/datatables/repository/DataTablesUtils.java
index 2fa5254..211b1ae 100644
--- a/src/main/java/org/springframework/data/jpa/datatables/repository/DataTablesUtils.java
+++ b/src/main/java/org/springframework/data/jpa/datatables/repository/DataTablesUtils.java
@@ -7,9 +7,11 @@
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.From;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.Attribute.PersistentAttributeType;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@@ -193,10 +195,16 @@ private static Expression getExpression(Root> root, String columnData)
if (columnData.contains(ATTRIBUTE_SEPARATOR)) {
// columnData is like "joinedEntity.attribute" so add a join clause
String[] values = columnData.split("\\" + ATTRIBUTE_SEPARATOR);
- if (!root.getModel().getAttribute(values[0]).isAssociation()) {
+ if (root.getModel().getAttribute(values[0])
+ .getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) {
+ // with @Embedded attribute
return root.get(values[0]).get(values[1]).as(String.class);
}
- return root.join(values[0], JoinType.LEFT).get(values[1]).as(String.class);
+ From, ?> from = root;
+ for (int i = 0; i < values.length - 1; i++) {
+ from = from.join(values[i], JoinType.LEFT);
+ }
+ return from.get(values[values.length - 1]).as(String.class);
} else {
// columnData is like "attribute" so nothing particular to do
return root.get(columnData).as(String.class);
diff --git a/src/test/java/org/springframework/data/jpa/datatables/Config.java b/src/test/java/org/springframework/data/jpa/datatables/Config.java
index 98c414a..3daad8f 100644
--- a/src/test/java/org/springframework/data/jpa/datatables/Config.java
+++ b/src/test/java/org/springframework/data/jpa/datatables/Config.java
@@ -1,9 +1,12 @@
package org.springframework.data.jpa.datatables;
import java.sql.SQLException;
+import java.util.Properties;
import javax.sql.DataSource;
+import org.hibernate.cfg.Environment;
+import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.datatables.repository.DataTablesRepositoryFactoryBean;
@@ -48,6 +51,13 @@ public AbstractEntityManagerFactoryBean entityManagerFactory() throws SQLExcepti
bean.setPackagesToScan(Config.class.getPackage().getName());
bean.setDataSource(dataSource());
+ Properties jpaProperties = new Properties();
+ jpaProperties.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
+ jpaProperties.setProperty(Environment.HBM2DDL_IMPORT_FILES, "init.sql");
+ jpaProperties.setProperty(Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR,
+ MultipleLinesSqlCommandExtractor.class.getName());
+ bean.setJpaProperties(jpaProperties);
+
return bean;
}
}
diff --git a/src/test/java/org/springframework/data/jpa/datatables/model/Course.java b/src/test/java/org/springframework/data/jpa/datatables/model/Course.java
new file mode 100644
index 0000000..88bf53f
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/datatables/model/Course.java
@@ -0,0 +1,47 @@
+package org.springframework.data.jpa.datatables.model;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "course")
+public class Course {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "course_type_id")
+ private CourseType type;
+
+ public Course() {}
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public CourseType getType() {
+ return type;
+ }
+
+ public void setType(CourseType type) {
+ this.type = type;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/datatables/model/CourseType.java b/src/test/java/org/springframework/data/jpa/datatables/model/CourseType.java
new file mode 100644
index 0000000..3f9d959
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/datatables/model/CourseType.java
@@ -0,0 +1,32 @@
+package org.springframework.data.jpa.datatables.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "course_type")
+public class CourseType {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ public CourseType() {}
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/datatables/model/Lesson.java b/src/test/java/org/springframework/data/jpa/datatables/model/Lesson.java
new file mode 100644
index 0000000..82202f2
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/datatables/model/Lesson.java
@@ -0,0 +1,47 @@
+package org.springframework.data.jpa.datatables.model;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "lesson")
+public class Lesson {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "course_id")
+ private Course course;
+
+ public Lesson() {}
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Course getCourse() {
+ return course;
+ }
+
+ public void setCourse(Course course) {
+ this.course = course;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/datatables/model/LessonRepository.java b/src/test/java/org/springframework/data/jpa/datatables/model/LessonRepository.java
new file mode 100644
index 0000000..71d1ed6
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/datatables/model/LessonRepository.java
@@ -0,0 +1,7 @@
+package org.springframework.data.jpa.datatables.model;
+
+import org.springframework.data.jpa.datatables.repository.DataTablesRepository;
+
+public interface LessonRepository extends DataTablesRepository {
+
+}
diff --git a/src/test/java/org/springframework/data/jpa/datatables/repository/LessonRepositoryTest.java b/src/test/java/org/springframework/data/jpa/datatables/repository/LessonRepositoryTest.java
new file mode 100644
index 0000000..9396280
--- /dev/null
+++ b/src/test/java/org/springframework/data/jpa/datatables/repository/LessonRepositoryTest.java
@@ -0,0 +1,74 @@
+package org.springframework.data.jpa.datatables.repository;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.datatables.Config;
+import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
+import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;
+import org.springframework.data.jpa.datatables.model.Lesson;
+import org.springframework.data.jpa.datatables.model.LessonRepository;
+import org.springframework.data.jpa.datatables.parameter.ColumnParameter;
+import org.springframework.data.jpa.datatables.parameter.OrderParameter;
+import org.springframework.data.jpa.datatables.parameter.SearchParameter;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = Config.class)
+public class LessonRepositoryTest {
+
+ @Autowired
+ private LessonRepository lessonRepository;
+
+ @Test
+ public void testThroughTwoManyToOneRelationships() {
+ DataTablesInput input = getBasicInput();
+
+ input.getColumns().get(3).getSearch().setValue("CourseTypeA");
+ DataTablesOutput output = lessonRepository.findAll(input);
+ assertNotNull(output);
+ assertNull(output.getError());
+ assertEquals(5, (long) output.getRecordsFiltered());
+ assertEquals(7, (long) output.getRecordsTotal());
+
+ input.getColumns().get(2).getSearch().setValue("CourseA-2");
+ output = lessonRepository.findAll(input);
+ assertNotNull(output);
+ assertNull(output.getError());
+ assertEquals(2, (long) output.getRecordsFiltered());
+ assertEquals(7, (long) output.getRecordsTotal());
+ }
+
+ /**
+ *
+ * @return basic input parameters
+ */
+ private static DataTablesInput getBasicInput() {
+ DataTablesInput input = new DataTablesInput();
+ input.setDraw(1);
+ input.setStart(0);
+ input.setLength(10);
+ input.setSearch(new SearchParameter("", false));
+ input.setOrder(new ArrayList());
+ input.getOrder().add(new OrderParameter(0, "asc"));
+
+ input.setColumns(new ArrayList());
+ input.getColumns()
+ .add(new ColumnParameter("id", "", true, true, new SearchParameter("", false)));
+ input.getColumns()
+ .add(new ColumnParameter("name", "", true, true, new SearchParameter("", false)));
+ input.getColumns()
+ .add(new ColumnParameter("course.name", "", true, true, new SearchParameter("", false)));
+ input.getColumns().add(
+ new ColumnParameter("course.type.name", "", true, true, new SearchParameter("", false)));
+
+ return input;
+ }
+}
diff --git a/src/test/resources/init.sql b/src/test/resources/init.sql
new file mode 100644
index 0000000..740228b
--- /dev/null
+++ b/src/test/resources/init.sql
@@ -0,0 +1,19 @@
+INSERT INTO course_type (id, name) VALUES
+ (1, 'CourseTypeA'),
+ (2, 'CourseTypeB'),
+ (3, 'CourseTypeC');
+
+INSERT INTO course (id, name, course_type_id) VALUES
+ (1, 'CourseA-1', 1),
+ (2, 'CourseA-2', 1),
+ (3, 'CourseA-3', 1),
+ (4, 'CourseB-1', 2);
+
+INSERT INTO lesson (id, name, course_id) VALUES
+ (1, 'LessonA-1-a', 1),
+ (2, 'LessonA-1-b', 1),
+ (3, 'LessonA-1-c', 1),
+ (4, 'LessonA-2-a', 2),
+ (5, 'LessonA-2-b', 2),
+ (6, 'LessonB-1-a', 4),
+ (7, 'LessonB-1-b', 4);