Hibernate left join fetch 对子集执行附加查询
Posted
技术标签:
【中文标题】Hibernate left join fetch 对子集执行附加查询【英文标题】:Hibernate left join fetch performing additional query for subset 【发布时间】:2021-11-26 09:20:45 【问题描述】:我想在一个查询中查询 date_to 等于 null 的具有分配的角色。 我需要返回所有角色,即使是那些没有分配任务的角色。
角色实体中的关系已设置:
@OneToMany(mappedBy = "role")
private List<Assignment> assignment;
Assignment Entity 与 Permission 有关系:
@ManyToMany
@JoinTable(
name = "assignment_version_permission",
joinColumns = @JoinColumn(name = "assignment_version_id"),
inverseJoinColumns = @JoinColumn(name = "permission_id"))
private Set<Permission> permissions;
@Column(name = "date_to")
private LocalDateTime dateTo;
并来自权限实体:
@ManyToMany
@JoinTable(
name = "assignment_version_permission",
joinColumns = @JoinColumn(name = "permission_id"),
inverseJoinColumns = @JoinColumn(name = "assignment_version_id"))
@ToString.Exclude
private List<Assignment> assignments;
我尝试仅在 date_to 等于 null 的情况下查询所有角色及其分配。
@Query("from Role r left join Assignment av on r.dbid = av.role.dbid and av.dateTo is null left join av.permissions p where r.name in :names")
List<Role> readByRoleNameInOnlyActiveAssignments (List<String> names);
上述查询有效,但在 role.getAssignemts() 之后 如果没有分配,我只想接收 date_to 为 null 或 null 的分配。
现在 role.getAssignemts() 对所有与角色相关的分配进行额外查询。当一个角色没有活动的分配时,我不想收到任何一个。我怎样才能实现它?
我尝试使用 EntityGraph,但没有选项可以在 assignemns 上添加条件(仅返回 assignment date_to 为 null 的这些)
@EntityGraph(attributePaths = "assignments", "assignments.permissions")
List<Role> readByNameIn(List<String> names);
【问题讨论】:
【参考方案1】:这不是直接可能的,因为仅获取集合的子集是不安全的。如果您更改集合,被过滤掉的元素将在集合重新创建事件中被删除,这就是为什么不允许对获取连接应用 ON 条件的原因。您看到的第二个查询是因为 Hibernate 不知道您加入的作业对应于 assignments
关联。
实现这一点的唯一方法是使用 DTO 方法,我认为这是 Blaze-Persistence Entity Views 的完美用例。
我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:
@EntityView(Role.class)
public interface RoleDto
@IdMapping
Long getId();
String getName();
@Mapping("assignments[dateTo IS NULL]")
Set<AssignmentDto> getAssignments();
@EntityView(Assignment.class)
interface AssignmentDto
@IdMapping
Long getId();
Set<PermissionDto> getPermissions();
@EntityView(Permission.class)
interface PermissionDto
@IdMapping
Long getId();
String getAction();
查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。
RoleDto a = entityViewManager.find(entityManager, RoleDto.class, id);
Spring Data 集成让您可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<RoleDto> findAll(Pageable pageable);
或者在你的情况下
List<RoleDto> findAllByNameIn(List<String> names);
最好的部分是,它只会获取实际需要的状态!
【讨论】:
以上是关于Hibernate left join fetch 对子集执行附加查询的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate中,left joininner join以及left join fetch区别(转)
Hibernate left join fetch 对子集执行附加查询
使用JPA和Hibernate时JOIN和JOIN FETCH有啥区别
Hibernate 在第一次 fetch-joining 然后 simple-joining 时不生成 JOIN