jpg*_*z18 8 java spring jpql spring-data-jpa
我遇到了一个问题,我不知道是否有可能使用JPA.
我正在尝试使用JPA进行查询并进行以下操作:
获取课程实体字段(id,name)的所有课程,但也包含非持久字段(@Transient),其中将填写与此课程相关的所有学生的计数
像这样的东西:
List<Course> courses = courseRepository.findAll();
Run Code Online (Sandbox Code Playgroud)
但取而代之的是(以json为例)
[{1, soccer}, {2, art}, {3, singing}]
Run Code Online (Sandbox Code Playgroud)
我需要这样的东西
[{1, soccer, 2}, {2, art, 0}, {3, singing, 1}]
Run Code Online (Sandbox Code Playgroud)
如您所见,值为2,0 a 1是所有相关行的表学生的计数
Student table
| id | name | description | course |
| 1 | thg1 | a thing | 1 |
| 2 | thg2 | another one | 1 |
| 3 | thg3 | one more | 3 |
Course Table
| id | name |
| 1 | soccer |
| 2 | art |
| 3 | singing |
Run Code Online (Sandbox Code Playgroud)
因此,限制是一名学生只能参加一门课程.
使用JPA我想选择所有课程,但由于我使用分页,我无法在春季部分(我的意思是作为服务),我试图直接用JPA做,有什么办法我可以实现这个吗?也许有规格?想法?
谢谢
您可以使用@FormulaHibernate中的注释:
@Formula("select count(*) FROM student s WHERE s.course = id")
private int totalStudents;
Run Code Online (Sandbox Code Playgroud)
有时,您希望数据库为您做一些计算而不是在JVM中进行计算,您可能还会创建某种虚拟列。您可以使用SQL片段(也称为公式)来代替将属性映射到列中。这种属性是只读的(其值由您的公式片段计算得出)。
Run Code Online (Sandbox Code Playgroud)@Formula("obj_length * obj_height * obj_width") public long getObjectVolume()SQL片段可以任意复杂,甚至可以包含子选择。
或者,您可以使用双向关系来计算学生:
@OneToMany(mappedBy="course")
private List<Student> students;
public int getTotalStudents() {
return students.size();
}
Run Code Online (Sandbox Code Playgroud)
或带有transient字段:
@OneToMany(mappedBy="course")
private List<Student> students;
@Transient
private int studentCount;
@PostLoad
public void setStudentCount() {
studentCount = students.size();
}
Run Code Online (Sandbox Code Playgroud)
为了避免Cepr0提到的N + 1问题,可以将获取模式设置为join:
@OneToMany(mappedBy="course")
@Fetch(FetchMode.JOIN)
private List<Student> students;
Run Code Online (Sandbox Code Playgroud)
您可以使用投影来实现您所需要的。
假设您正在使用以下实体:
@Entity
@Data
@AllArgsConstructor
public class Course implements Serializable {
@Id
@GeneratedValue
private Integer id;
private String name;
@Transient
private Long total;
public Course() {
}
public Course(String name) {
this.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@Data
@AllArgsConstructor
public class Student implements Serializable {
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToOne(optional = false)
private Course course;
public Student() {
}
public Student(String name, Course course) {
this.name = name;
this.course = course;
}
}
Run Code Online (Sandbox Code Playgroud)
1)然后你可以创建基于界面的投影
public interface CourseWithCountProjection {
Integer getId();
String getName();
Long getTotal();
}
Run Code Online (Sandbox Code Playgroud)
以及课程存储库中的以下查询方法:
public interface CourseRepo extends JpaRepository<Course, Integer> {
@Query(value = "" +
"select " +
" c.id as id, " +
" c.name as name, " +
" count(s) as total " +
"from " +
" Course c " +
" left join Student s on s.course.id = c.id " +
"group by " +
" c " +
"order by " +
" count(s) desc" +
"", countQuery = "select count(c) from Course c")
Page<CourseWithCountProjection> getProjectionWithCount(Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您不需要total中的瞬态字段Course,并且可以将其删除。
请注意,您必须将额外的countQuery参数添加到注释中@Query,因为主查询具有分组。
还要注意查询中的别名(c.id as id等) - 当您使用投影时它们是必要的。
2)另一种方法是在 JPQL 查询中使用Course构造函数,如 @KarolDowbecki 所示。您可以将它用于几乎相同的查询:
public interface CourseRepo extends JpaRepository<Course, Integer> {
@Query(value = "" +
"select " +
" new Course(c.id, c.name, count(s)) " +
"from " +
" Course c " +
" left join Student s on s.course.id = c.id " +
"group by " +
" c " +
"order by " +
" count(s) desc" +
"", countQuery = "select count(c) from Course c")
Page<Course> getCoursesWithCount(Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)
更新
第一个选项更可取,因为它将模型( Course) 和视图( CourseWithCountProjection) 分开。
更新2
要获得动态排序,您可以order by从查询中排除并在Pageable查询方法的参数中提供排序,例如:
@Query(value = "" +
"select " +
" c.id as id, " +
" c.name as name, " +
" count(s) as total " +
"from " +
" Course c " +
" left join Student s on s.course.id = c.id " +
"group by " +
" c " +
"", countQuery = "select count(c) from Course c")
Page<CourseWithCountProjection> getProjectionWithCount(Pageable pageable);
Page<CourseWithCountProjection> result = parentRepo.getProjectionWithCount(PageRequest.of(0, 20, Sort.by(Sort.Direction.DESC, "total")));
Run Code Online (Sandbox Code Playgroud)
工作示例在这里:sb-jpa-orderby-相关
| 归档时间: |
|
| 查看次数: |
959 次 |
| 最近记录: |