如何在 JpaRepository 中定义自定义的 findAll 方法?
How to define custom findAll methods in JpaRepository?
我有两个 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 中使用什么实体图?或者这是无法通过这种方式实现的,我需要创建自定义存储库实现吗?
但是你有这个查询:
LEFT OUTER JOIN countries country1_ ON
post0_.country_id = country1_.id
LIMIT
是不是有点像“where country_id =”。
您是否 运行 对示例数据库进行了此查询,看看得到了什么?也许它只是工作正常。
另外,我想,你可以直接说
findAllPostResourcesByCountryId(long countryId);
抱歉,我很想发表评论而不是回答,但我没有足够的声誉。
我找到了我的问题的解决方案:如何同时使用 Predicate、Pageable 和 EntityGraph 的方法,答案是使用以下库:
我有两个 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 中使用什么实体图?或者这是无法通过这种方式实现的,我需要创建自定义存储库实现吗?
但是你有这个查询:
LEFT OUTER JOIN countries country1_ ON
post0_.country_id = country1_.id
LIMIT
是不是有点像“where country_id =”。 您是否 运行 对示例数据库进行了此查询,看看得到了什么?也许它只是工作正常。
另外,我想,你可以直接说
findAllPostResourcesByCountryId(long countryId);
抱歉,我很想发表评论而不是回答,但我没有足够的声誉。
我找到了我的问题的解决方案:如何同时使用 Predicate、Pageable 和 EntityGraph 的方法,答案是使用以下库: