具有自定义查询和可分页参数的Spring Data JPA存储库方法的默认排序

时间:2016-07-27 13:23:07

标签: spring-data-jpa spring-data-rest

如果用户在page参数中提供排序列,我有以下存储库方法,完全符合我的需要:

public interface IdentityRepository extends JpaRepository<Identity, String> {

    @Query("select distinct ident from Identity ident left outer join ident.authorities authority "
        + "where ("
            + "(:src is null or ident.source = :src) and "
            + "(:org is null or ident.organization = :org) and "
            + "(:auth is null or authority.authority = :auth) and "
            + "(:authSrc is null or authority.authoritySource = :authSrc))")
    @RestResource(path="filter")
    public Page<Identity> findWithFilter(
        @Param("src") String source, 
        @Param("org") String org, 
        @Param("auth") Authority auth, 
        @Param("authSrc") AuthoritySource authSrc, 
        Pageable page);
...
}

如果调用者提供了页数而不是排序列,则在检索所有页面时,他们将返回正确的结果。但是,许多实体将被复制,因此即使结果计数正确,也会丢失许多预期实体,而其他实体则重复(或重复)。

我想知道的是,如果用户没有指定默认排序列和方向,是否有办法提供。我已经知道@EnableSpringDataWebSupport可以在这里提供帮助,但是我们没有使用Spring MVC,所以我没有任何控制器来附加@SortDefaults。我们正在使用Spring Data Rest。此外,我已尝试将方法名称更改为findWithFilterOrderByIdAsc,但这似乎没有帮助。在Spring JIRA中跨过this issue,我相信这正是我所需要的,但在它解决之前,有没有人知道一个解决方法?

这是我的实体......

@Entity
@Table(name = "identity", indexes = { @Index(columnList = "user_id", unique = true) })
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Audited
public class Identity implements Serializable, Identifiable<String> {

    /** 
     * The unique identifier for this identity within the IDD application.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "IDDUidGenerator")
    @GenericGenerator(name = "IDDUidGenerator")
    private String id;
    /**
     * The name of the identity provider wherein this identity is originally defined.
     */
    @Column(name = "source")
    private String source = INTERNAL_SOURCE;
    /**
     * The unique identifier for this identity within the customer's identity provider.
     */
    @NotNull
    @Column(name = "user_id", nullable = false, unique = true)
    private String userId;
    /**
     * The roles this identity is authorized to perform.
     */
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "identity", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<IdentityAuthority> authorities = new HashSet<>();
...
}

及其子实体......

@Entity
@Table(name = "identity_authority")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Audited
public class IdentityAuthority implements Serializable, Identifiable<Long> {

    private static final long serialVersionUID = -5315412946768343445L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @XmlTransient
    @JsonIgnore
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "identity_id", nullable = false)
    @XmlTransient
    @JsonIgnore
    private Identity identity;

    @Enumerated(EnumType.STRING)
    @Column(name = "authority", length = 20, nullable = false)
    private Authority authority;

    @Enumerated(EnumType.STRING)
    @Column(name = "authority_source", length = 30, nullable = false)
    private AuthoritySource authoritySource;
...
}

这是我为证明问题而运行的测试案例......

@Test
public void testPagedRequestsReturnAllResults() {
    // Create identities
    String source = "One Hundred Identities Generator";
    int numIdentities = 100;
    int pageSize = 5;
    List<Identity> input = new ArrayList<>();
    for (int i=0; i<numIdentities; i++) {
        Identity identity = new Identity();
        identity.setUserId(UUID.randomUUID().toString());
        identity.setSource(source);
        input.add(identity);
    }

    // Save identities
    List<Identity> output = repository.saveBulk(input);
    Set<String> savedIds = collectIds(output, null);
    assertThat(savedIds.size()).isEqualTo(numIdentities);

    // Test Sorted Find Filter with Paging (THIS PASSES)
    Pageable pageRequest = new PageRequest(0, pageSize, new Sort(Direction.ASC, "id"));
    Set<String> foundPagedIds = new HashSet<>();
    do {
        Page<Identity> page = repository.findOrderByIdAsc(source, null, null, null, pageRequest);
        List<Identity> foundIdentities = page.getContent();
        foundPagedIds = collectIds(foundIdentities, foundPagedIds);
        pageRequest = page.nextPageable();
    } while (pageRequest != null);
    assertThat(foundPagedIds.size()).isEqualTo(numIdentities);
    assertThat(foundPagedIds).isEqualTo(savedIds);

    // Test Unsorted Find Filter with Paging (THIS FAILS)
    pageRequest = new PageRequest(0, pageSize);
    foundPagedIds = new HashSet<>();
    do {
        Page<Identity> page = repository.findOrderByIdAsc(source, null, null, null, pageRequest);
        List<Identity> foundIdentities = page.getContent();
        foundPagedIds = collectIds(foundIdentities, foundPagedIds);
        pageRequest = page.nextPageable();
    } while (pageRequest != null);
    assertThat(foundPagedIds.size()).isEqualTo(numIdentities);
    assertThat(foundPagedIds).isEqualTo(savedIds);
}

0 个答案:

没有答案