(Spring Data JPA)合并@ JuttyGraph和Specification在中生成单个JOIN

hm2xizp9  于 8个月前  发布在  Spring
关注(0)|答案(1)|浏览(87)

我想在Spring Data JPA中结合合并@ JuttyGraph和Specification来生成一个JOIN子句,而不是单独的JOIN子句。

@Entity
public class LoginUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(nullable = false)
    private String name;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_role",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private List<Role> roleList;
}

@Entity
public class Role {
    @Id
    private Integer id;

    @Column(nullable = false)
    private String name;
}

public interface LoginUserRepository extends JpaRepository<LoginUser, String>,
        JpaSpecificationExecutor<LoginUser> {

    @EntityGraph(attributePaths = {"roleList"})
    public Page<LoginUser> findAll(Specification<LoginUser> spec, Pageable pageable);
}

public class LoginUserSpecification {
   static public Specification<LoginUser> equalsRole(String role) {
        return (root, query, builder) -> builder.equal(
                    root.join("roleList", JoinType.LEFT).get("name"), role);
    }
}

public class LoginUserDetailsService {
    public Page<LoginUser> getAccounts(Pageable pageable, UserSearchForm form) {
        return loginUserRepository.findAll(
                Specification.where(LoginUserSpecification.equalsRole(form.getRole())),
                pageable);
    }
}

生成的SQL:

select
    l1_0.id,
    l1_0.name,
    r2_0.user_id,
    r2_1.id,
    r2_1.name
from
    login_user l1_0
left
    join ( /* JOIN clause generated by Specification */
        user_role r1_0
        join roles r1_1 on r1_1.id = r1_0.role_id
    )
    on l1_0.id = r1_0.user_id
left
    join ( /* JOIN clause generated by @EntityGraph */
        user_role r2_0
        join roles r2_1 on r2_1.id = r2_0.role_id
    )
    on l1_0.id = r2_0.user_id
where
    r1_1.name = 'ROLE_ADMIN'

预期SQL:

select
    l1_0.id,
    l1_0.name,
    r2_0.user_id,
    r2_1.id,
    r2_1.name
from
    login_user l1_0
left
    join ( /* JOIN clause generated by @EntityGraph */
        user_role r2_0
        join roles r2_1 on r2_1.id = r2_0.role_id
    )
    on l1_0.id = r2_0.user_id
where
    r2_1.name = 'ROLE_ADMIN'

是否有可能将重复的JOIN子句合并为一个如上所述的单独子句?

root.join("roleList", JoinType.LFET).get("name"), role);

理想情况下,在指定搜索条件时,JoinType.INNER是合适的。但是,我选择了LEFT,希望它可以优化查询。

pdkcd3nj

pdkcd3nj1#

我找不到一个方法来做到这一点,所以我改变了SQL和处理它。具体来说,我将规范更改为exists子句。

select
    l1_0.id,
    l1_0.name,
    r2_0.user_id,
    r2_1.id,
    r2_1.name
from
    login_user l1_0
left
    join ( /* JOIN clause generated by @EntityGraph */
        user_role r2_0
        join roles r2_1 on r2_1.id = r2_0.role_id
    )
    on l1_0.id = r2_0.user_id
where
    exists (
        select
            1
        from
            login_user l2_0
            join (
                user_role r2_0
                join roles r2_1 on r2_1.id = r2_0.role_id
            )
            on l2_0.id = r2_0.user_id
        where
            l1_0.id = l2_0.id
            and
            r2_1.name in (
                'ROLE_ADMIN'
            )
    )

相关问题