【问题标题】:How to define custom findAll methods in JpaRepository?如何在 JpaRepository 中定义自定义 findAll 方法?
【发布时间】:2020-06-29 11:43:20
【问题描述】:

我有两个 api 端点:

  • /api/posts - 获取分页帖子列表
  • /api/countries/{country}/posts - 按国家/地区获取分页帖子列表

所以我有以下实体:

@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
@NamedEntityGraph(
    name = "Post.Resource",
    attributeNodes = @NamedAttributeNode("country")
)
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String title;
    private String body;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "country_id")
    private Country country;

    @Column(name = "published_at")
    private LocalDateTime publishedAt;

    @CreatedDate
    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    public boolean isPublished() {
        return publishedAt != null;
    }

    public boolean isDraft() {
        return !isPublished();
    }
}

我已经定义了以下存储库。请注意,我是如何为最后两个方法定义实体图的,我需要这样,因为我不想覆盖 findAll() 方法,因为将来我需要加载没有任何关系的帖子。还有一件事我希望它成为谓词,以便在各种不同的服务中我可以重用方法,而不是为每个查询创建方法...

@Repository
public interface PostRepository extends JpaRepository<Post, Long>, 
    JpaSpecificationExecutor<Post>, 
    QuerydslPredicateExecutor<Post> 
{
    @EntityGraph("Post.Resource")
    Optional<Post> findPostResourceById(long id);

    @Query("SELECT post FROM Post post")
    @EntityGraph("Post.Resource")
    Page<Post> findAllPostResources(Pageable pageable);

    @Query("SELECT post FROM Post post")
    @EntityGraph("Post.Resource")
    Page<Post> findAllPostResources(Predicate predicate, Pageable pageable);
}

问题是当我使用谓词和可分页参数调用findAllPostResources 时:

public Page<Post> getAllPostsByCountryPaginated(long countryId, Pageable pageable) {
    return postRepository.findAllPostResources(QPost.post.country.id.eq(countryId), pageable);
}

它忽略谓词参数并执行以下查询:

SELECT
    post0_.id AS id1_13_0_,
    country1_.id AS id1_3_1_,
    post0_.body AS body2_13_0_,
    post0_.country_id AS country_7_13_0_,
    post0_.created_at AS created_3_13_0_,
    post0_.published_at AS publishe4_13_0_,
    post0_.title AS title5_13_0_,
    post0_.updated_at AS updated_6_13_0_,
    country1_.alpha2_code AS alpha2_3_1_,
    country1_.alpha3_code AS alpha3_3_1_,
    country1_.created_at AS created_4_3_1_,
    country1_.name AS name5_3_1_,
    country1_.updated_at AS updated_6_3_1_
FROM
    posts post0_
LEFT OUTER JOIN countries country1_ ON
    post0_.country_id = country1_.id
LIMIT ?

如您所见,SQL (WHERE country_id = ?) 中没有 WHERE 原因。

那么,如何创建 findAll() 方法并定义谓词、分页以及在 JpaRepository 中使用什么实体图?或者这是无法通过这种方式实现的,我需要创建自定义存储库实现?

【问题讨论】:

  • 您要么编写查询并使用可分页,要么传递谓词和可分页而不使用查询。将查询和谓词结合起来是行不通的。
  • 可能duplicate

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


【解决方案1】:

我找到了解决问题的方法:如何同时使用 Predicate、Pageable 和 EntityGraph 的方法,答案是使用以下库:

https://github.com/Cosium/spring-data-jpa-entity-graph

【讨论】:

    【解决方案2】:

    但你有这个查询:

    LEFT OUTER JOIN countries country1_ ON
        post0_.country_id = country1_.id
    LIMIT
    

    这和“where country_id =”不一样吗? 您是否在示例数据库上运行此查询并查看您得到了什么?也许它工作得很好。

    另外,我认为,你可以说

    findAllPostResourcesByCountryId(long countryId);
    

    对不起,我很想发表评论而不是回答,但我没有足够的声誉。

    【讨论】:

    • 那行得通,但是我会为每个查询提供方法,而我想有一个方法并让服务定义搜索条件......我确实在数据库上运行查询并从中获取帖子所有国家/地区,但我只想要特定国家/地区的帖子
    • 您需要为此创建自定义存储库实现,抱歉。
    猜你喜欢
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 2015-12-14
    • 1970-01-01
    • 2020-09-17
    • 2015-03-02
    相关资源
    最近更新 更多