【问题标题】:Hibernate left join fetch performing additional query for subsetHibernate left join fetch 对子集执行附加查询
【发布时间】: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);

【问题讨论】:

    标签: sql spring-boot hibernate jpa


    【解决方案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);
    

    最好的部分是,它只会获取实际需要的状态!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-13
      • 2021-10-19
      • 2015-01-30
      • 1970-01-01
      • 2012-02-12
      • 2021-01-28
      • 2012-04-15
      • 2013-04-07
      相关资源
      最近更新 更多