【问题标题】:Spring Data Filtering in Repositories methods存储库方法中的 Spring 数据过滤
【发布时间】:2016-07-02 07:06:44
【问题描述】:

在我的 Spring Boot/Data/JPA 2.1 应用程序中,我有以下实体:

@Entity
@NamedEntityGraph(name = "graph.CardCategoryLevel", attributeNodes = { @NamedAttributeNode("cardCategory"), @NamedAttributeNode("level") })
@Table(name = "card_categories_levels")
public class CardCategoryLevel extends BaseEntity implements Serializable {

    @Id
    @SequenceGenerator(name = "card_categories_levels_id_seq", sequenceName = "card_categories_levels_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "card_categories_levels_id_seq")
    private Long id;

    @OneToOne
    @JoinColumn(name = "card_category_id")
    private CardCategory cardCategory;

    @OneToOne
    @JoinColumn(name = "level_id")
    private Level level;

    @Column(name = "card_drop_rate")
    private Float cardDropRate;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "cardCategoryLevel")
    private List<Card> cards = new ArrayList<Card>();
....
}

和 Spring Data CardCategoryLevelRepository:

@Repository
public interface CardCategoryLevelRepository extends JpaRepository<CardCategoryLevel, Long> {

    @Override
    @EntityGraph(value = "graph.CardCategoryLevel", type = EntityGraphType.FETCH)
    Page<CardCategoryLevel> findAll(Pageable pageable);

}

基于CardCategoryLevelRepository.findAll(Pageable pageable),我可以通过分页和排序检索所有CardCategoryLevel

现在我不知道如何将过滤应用到这种方法中。例如,我需要有可能通过CardCategory 或/和Level 或/和cardDropRate 过滤CardCategoryLevel。如何将过滤功能注入CardCategoryLevelRepository.findAll(Pageable pageable) 方法或可能是新的类似方法?

【问题讨论】:

  • 您可以创建一个方法名称,spring 数据将从该方法名称创建查询(将导致巨大的方法名称),或者您可以将 @Query 添加到方法并提供过滤逻辑。见docs.spring.io/spring-data/jpa/docs/current/reference/html/…
  • @BalajiKrishnan 例如,我将添加以下方法:findByCardCategoryAndLevelAndCardDropRate(cardCategory, level, cardDropRate) - 有什么方法可以根据cardDropRate 仅检索所有CardCategoryLevel 并跳过cardCategory 和@987654336 的过滤@?或者为了做到这一点,我需要为我的CardCategoryLevelRepository 为所有参数组合提供 3 种不同的方法?
  • 我可能错了,但是AFAIK你需要三种方法

标签: java spring jpa spring-data spring-data-jpa


【解决方案1】:

使用 QueryDSL 和实体图实现。现在我可以使用 QueryDSL 谓词应用过滤(另外,请为这个 BUG 投票https://jira.spring.io/browse/DATAJPA-684):

@Repository
public interface CardCategoryLevelRepository extends JpaRepository<CardCategoryLevel, Long>, QueryDslPredicateExecutor<CardCategoryLevel>, CardCategoryLevelRepositoryCustom {

    @Override
    @EntityGraph(value = "graph.CardCategoryLevel", type = EntityGraphType.LOAD)
    List<CardCategoryLevel> findAll(Predicate predicate);

....
}

public interface CardCategoryLevelRepositoryCustom {

    Page<CardCategoryLevel> findAll(Predicate predicate, Pageable pageable);

}

public class CardCategoryLevelRepositoryImpl extends SimpleJpaRepository<CardCategoryLevel, Long> implements CardCategoryLevelRepositoryCustom {

    private final EntityManager entityManager;
    private final EntityPath<CardCategoryLevel> path;
    private final PathBuilder<CardCategoryLevel> builder;
    private final Querydsl querydsl;

    /**
     * Workaround, must be removed once fixed
     * https://jira.spring.io/browse/DATAJPA-684
     * http://stackoverflow.com/questions/36043665/querydsl-query-specified-join-fetching-but-the-owner-of-the-fetched-associati
     * 
     * @param entityManager
     */
    @Autowired
    public CardCategoryLevelRepositoryImpl(EntityManager entityManager) {
        super(CardCategoryLevel.class, entityManager);

        this.entityManager = entityManager;
        this.path = SimpleEntityPathResolver.INSTANCE.createPath(CardCategoryLevel.class);
        this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
        this.querydsl = new Querydsl(entityManager, builder);
    }

    /**
     * Workaround, must be removed once fixed
     * https://jira.spring.io/browse/DATAJPA-684
     * http://stackoverflow.com/questions/36043665/querydsl-query-specified-join-fetching-but-the-owner-of-the-fetched-associati
     */
    @Override
    public Page<CardCategoryLevel> findAll(Predicate predicate, Pageable pageable) {
        JPAQuery countQuery = createQuery(predicate);
        JPAQuery query = (JPAQuery) querydsl.applyPagination(pageable, createQuery(predicate));

        query.setHint(EntityGraph.EntityGraphType.LOAD.getKey(), entityManager.getEntityGraph("graph.CardCategoryLevel"));

        Long total = countQuery.count();
        List<CardCategoryLevel> content = total > pageable.getOffset() ? query.list(path) : Collections.<CardCategoryLevel> emptyList();

        return new PageImpl<>(content, pageable, total);
    }

    private JPAQuery createQuery(Predicate predicate) {
        return querydsl.createQuery(path).where(predicate);
    }

}

【讨论】:

    猜你喜欢
    • 2020-02-23
    • 2020-07-12
    • 2020-06-17
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    相关资源
    最近更新 更多