是的,使用的时候会根据不同的业务进行各种多表联查,比如我们拥有如下对象:public class Post {
private long id;
private String title;
private String content;
@ManyToOne
private User creator;
...
}
public class User {
private long id;
private String email;
private String userName;
...
}
此时,我们知道,Post表中creator字段存储的是User的id。通常情况下,我们可以根据User对象来获取某个用户创建的所有博客:List findByCreator(User user);
但是在这种方式下,如果我们只知道用户的userName,我们就必须通过UserRepository先拿到User对象,再调用上述方法得到某个用户创建的所有博客。
实际上,我们通常会通过连表查询的方式一次性拿到相应的数据。在JPA里面,通常有下面两种方法:
通过方法名定义
我们可以通过如下语句去定义一个连表查询,List findByCreatorUserName(String userName);
此时,Spring Data JPA将按照以下顺序创建查询语句:首先查找Post对象中是否有creatorUserName属性,如果有,则直接生成查询语句… where x.creatorUserName = ?1,我们的Post对象并没有该属性,进入下一步
查找是否含有creatorUser属性,如果有,则看creatorUser是否含有name属性,如果有,则生成相应的查询语句,我们的Post对象并没有该属性,进入下一步
查找是否有creator属性,如果依然没有,则抛出错误PropertyReferenceException,我们的Post对象存在该属性,进入下一步
查找creator是否含有userName属性,若没有,依然抛出PropertyReferenceException,我们的User对象存在该属性,进入下一步
由于creator存在userName属性,生成查询语句… where x.creator.userName = ?1
我们可以看到,属性表达式通过字母的大小写来与实体对象的属性进行关联。但是,如果在Post对象中恰巧有creatorUserName这个属性,那么,Spring Data JPA将会在第一步就完成查询语句的生成,但是,这并不是我们所希望的结果。此时,我们可以通过_来控制属性表达式:
List findByCreator_UserName(String userName);
此时,Spring Data JPA的属性表达式将直接寻找creator属性下的userName属性。
通过@Query标注定义
在JPA中,实际上是可以自己写sql语句的,方法如下:
@Query("select * from post inner join user on post.creator = user.id where user.userName = ?1;", nativeQuery = true)
List findByUser(String userName);
通常情况下,通过方法名已经可以满足我们的大部分需求,但是在少数特别复杂的情况下,我们就可以通过@Query标注来实现连表查询