在JPA中,使用实体图查询具有自定义中间表的多对多实体
· 阅读需 9 分钟
大家好哇!不知道大家在使用JPA的时候有没有试用过实体图(EntityGraph
)进行查询呢?它的功能很强大,
比如可以用来规避大家经常遇到的 n+1 的问题。
那么你了不了解如何在"自定义中间表"的情况下去使用实体图查询呢?如果不太了解,那么就来跟着我看一下吧!
为了方便演示,后续的项目环境默认视为在
spring-boot-starter-data-jpa
中喔~
实体定义
首先,我们先来看看普通的多对多实体是如何定义、查询的。假设:我们有一个账户(account
)和权限(permission
)表,
它们之间是多对多关系,中间表为 account_permission
。
那么,先来定义它们的实体类:
// Account.java
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false)
private String name;
@ManyToMany
@JoinTable(name = "account_permission")
private Set<Permission> permissions = new HashSet<>();
}
// Permission.java
@Entity
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany(mappedBy = "permissions")
private Set<Account> accounts = new HashSet<>();
}
为了演示省事儿, 省略掉 getter、setter 之类的东西咯。
然后,在 Account
中添加实体图描述。
@Entity
@NamedEntityGraph(
name = Account.ALL_GRAPH,
attributeNodes = {
@NamedAttributeNode("permissions")
}
)
public class Account {
public static final String ALL_GRAPH = "ACCOUNT.ALL";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false)
private String name;
@ManyToMany
@JoinTable(name = "account_permission")
private Set<Permission> permissions = new HashSet<>();
}
接下来,定义一个 Repository 并使用图查询,来看看效果:
public interface AccountRepository extends JpaRepository<Account, Integer> {
// 使用具有命名的图查询
@EntityGraph(Account.ALL_GRAPH)
List<Account> findAllBy();
}
@SpringBootTest(classes = {GraphTests.class, AccountRepository.class})
@ActiveProfiles("test")
@SpringBootApplication
public class GraphTests {
@Test
public void graphTest(
@Autowired AccountRepository accountRepository
) {
accountRepository.findAllBy();
}
}
当执行测试之后,我们便可以在日志中看到本次查询所生成的SQL:
select
a1_0.id,
a1_0.name,
p1_0.accounts_id,
p1_1.id,
p1_1.name
from
account a1_0
left join
(account_permission p1_0
join
permission p1_1
on p1_1.id=p1_0.permissions_id)
on a1_0.id=p1_0.accounts_id
可以看到,它帮我们自动进行了关联查询,避免了n+1的情况出现。