![](/img/trans.png)
[英]How to combine distinct and sort in spring data jpa specification query with joins
[英]How to write a Spring Data JPA Specification with multiple joins?
我正在處理的項目是使用支持實體過濾的JHipster生成的,該過濾器在后台使用了Spring Data JPA規范。
該模型如下(在JDL中):
entity Student {
name String
}
entity Course {
name String
}
entity Enrollment {
}
entity Attendance {
date LocalDate
}
relationship OneToMany {
Student to Enrollment(student required),
Course to Enrollment(course required),
Enrollment to Attendance(enrollment required)
}
filter all
service all with serviceClass
JHipster生成用於通過enrollmentId
過濾Attendance
的樣板,但我想對其進行擴展以能夠通過studentId
和courseId
進行過濾。
因此,如何實現將執行類似查詢的規范:
SELECT
attendance.date, student.name as student, course.name as course
FROM attendance
JOIN enrollment
ON enrollment.id = attendance.enrollment_id
JOIN student
ON student.id = enrollment.student_id
AND studend.id = 1
JOIN course
ON course.id = enrollment.course_id
AND course.id = 2;
遵循@GaëlMarziou的建議,我已經實現了一些簡單的方法來創建Specification<Attendance>
以便與Student
和Course
聯接 。
我將字段,獲取器和設置器添加到AttendanceCriteria
類,並重新編譯以更新JPA元模型:
private LongFilter studentId;
private LongFilter courseId;
public LongFilter getStudentId() {
return studentId;
}
public void setStudentId(LongFilter studentId) {
this.studentId = studentId;
}
public LongFilter getCourseId() {
return courseId;
}
public void setCourseId(LongFilter courseId) {
this.courseId = courseId;
}
這是AttencanceQueryService
類的更新的片段:
private Specification<Attendance> createSpecification(AttendanceCriteria criteria) {
Specification<Attendance> specification = Specification.where(null);
if (criteria != null) {
if (criteria.getId() != null) {
specification = specification.and(buildSpecification(criteria.getId(), Attendance_.id));
}
if (criteria.getDate() != null) {
specification = specification.and(buildRangeSpecification(criteria.getDate(), Attendance_.date));
}
if (criteria.getEnrollmentId() != null) {
specification = specification.and(buildReferringEntitySpecification(criteria.getEnrollmentId(), Attendance_.enrollment, Enrollment_.id));
}
if (criteria.getStudentId() != null) {
specification = specification.and(buildJoinSpecification(criteria.getStudentId(), Attendance_.enrollment, Enrollment_.student, Student_.id));
}
if (criteria.getCourseId() != null) {
specification = specification.and(buildJoinSpecification(criteria.getCourseId(), Attendance_.enrollment, Enrollment_.course, Course_.id));
}
}
return specification;
}
private <REFERENCE, JOIN, FILTER extends Comparable<? super FILTER>> Specification<Attendance> buildJoinSpecification(RangeFilter<FILTER> filter, SingularAttribute<? super Attendance, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> valueField) {
Specification<Attendance> result = Specification.where((Specification) null);
if (filter.getEquals() != null) {
result = this.equalsSpecification(reference, joinField, valueField, filter.getEquals());
}
if (filter.getIn() != null) {
result = this.valueIn((SingularAttribute) reference, joinField, valueField, filter.getIn());
}
return result;
}
private <REFERENCE, JOIN, FILTER> Specification<Attendance> equalsSpecification(SingularAttribute<? super Attendance, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> idField, FILTER value) {
return (root, query, builder) ->
builder.equal(root.join(reference).join(joinField).get(idField), value);
}
private <REFERENCE, JOIN, FILTER> Specification<Attendance> valueIn(SingularAttribute<? super Attendance, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> valueField, Collection<FILTER> values) {
return (root, query, builder) -> {
CriteriaBuilder.In<FILTER> in = builder.in(root.join(reference).join(joinField).get(valueField));
for (FILTER value : values) {
in = in.value(value);
}
return in;
};
}
我希望這對某人有幫助,功勞歸於@GaëlMarziou和Blackdread / Yoann Caplain 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.