Java 使用片段的Spring数据Jpa存储库如何应用查询提示和实体图
从Spring5开始,我们可以选择使用多个片段存储库来丰富我们的JPA存储库 机制非常简单:声明然后实现一个接口Java 使用片段的Spring数据Jpa存储库如何应用查询提示和实体图,java,jpa,spring-data-jpa,Java,Jpa,Spring Data Jpa,从Spring5开始,我们可以选择使用多个片段存储库来丰富我们的JPA存储库 机制非常简单:声明然后实现一个接口 public interface CustomRepository<T,K> { // my very special finder T findByIdCustom(K id); } 公共接口自定义存储库{ //我非常特别的发现者 T findByIdCustom(K id); } 公共类CustomRepositoryImpl实现CustomRep
public interface CustomRepository<T,K> {
// my very special finder
T findByIdCustom(K id);
}
公共接口自定义存储库{
//我非常特别的发现者
T findByIdCustom(K id);
}
公共类CustomRepositoryImpl实现CustomRepository{
T findByIdCustom(K id){
//检索项目
}
}
然后,像这样使用它:
public interface ItemRepository
extends JpaRepository<Item, Long>, CustomRepository<Item, Long> {
}
public interface ItemRepository extends JpaRepository<Item, Long>, CustomRepository<Item, Long>{
@QueryHints(value = { @QueryHint(name = "name", value = "value")},
forCounting = false)
@EntityGraph(value = "Item.characteristics")
Item findByIdCustom(Long id);
}
公共接口项目存储库
扩展JpaRepository、CustomRepository{
}
现在,假设我想设置一些查询提示和/或实体图,如下所示:
public interface ItemRepository
extends JpaRepository<Item, Long>, CustomRepository<Item, Long> {
}
public interface ItemRepository extends JpaRepository<Item, Long>, CustomRepository<Item, Long>{
@QueryHints(value = { @QueryHint(name = "name", value = "value")},
forCounting = false)
@EntityGraph(value = "Item.characteristics")
Item findByIdCustom(Long id);
}
public interface ItemRepository扩展了JpaRepository、CustomRepository{
@QueryHints(value={@QueryHint(name=“name”,value=“value”)},
forCounting=假)
@EntityGraph(value=“Item.characteristics”)
项目findByIdCustom(长id);
}
由于我有一个自定义的实现,所以在这里忽略了上面的查询提示和实体图,它们在JpaRepository
方法上工作得很好
我的问题是:
如何将该方法的元数据应用于基础查询?不能使用注释来实现您的要求,因为它们将与Spring提供实现的存储库方法一起使用。对于自定义方法,Spring必须忽略它——因为您的自定义代码负责构建、配置和执行查询,所以Spring无法神奇地中途介入并注入查询提示。本质上,如果您想要为自定义查询方法提供两组不同的提示,则需要两种不同的实现 但是,您可以尝试一种模板方法模式,如下所示:
public interface CustomRepository<T,K> {
T findByIdCustom(K id);
Map<String, Object> getHintsForFindByIdCustom();
// you'll probably need a default implementation for getHintsForFindByIdCustom here, unless it's possible to make CustomRepositoryImpl abstract - not sure how Spring Data will behave in this case
}
public class CustomRepositoryImpl<T, K> implements CustomRepository<T,K> {
T findByIdCustom(K id) {
TypedQuery<T> query= em.createQuery("...");
getHintsForFindByIdCustom().forEach((key, value) -> query.setHint(key, value));
return query.getResultList().iterator().next();
}
}
public interface ItemRepository extends JpaRepository<Item, Long>, CustomRepository<Item, Long>{
default Map<String, Object> getHintsForFindByIdCustom() {
return Map.of("name", "value");
}
}
public interface UserRepository extends JpaRepository<User, Long>, CustomRepository<User, Long>{
default Map<String, Object> getHintsForFindByIdCustom() {
return Map.of("name", "some-other-value");
}
}
公共接口自定义存储库{
T findByIdCustom(K id);
映射getHintsForFindByIdCustom();
//在这里,您可能需要getHintsForFindByIdCustom的默认实现,除非可以将CustomRepositoryImpl抽象化—不确定Spring数据在这种情况下的行为
}
公共类CustomRepositoryImpl实现CustomRepository{
T findByIdCustom(K id){
TypedQuery=em.createQuery(“…”);
getHintsForFindByIdCustom().forEach((键,值)->query.setHint(键,值));
返回query.getResultList().iterator().next();
}
}
公共接口ItemRepository扩展了JpaRepository、CustomRepository{
默认映射getHintsForFindByIdCustom(){
返回映射(“名称”、“值”);
}
}
公共接口UserRepository扩展了JpaRepository、CustomRepository{
默认映射getHintsForFindByIdCustom(){
返回映射(“名称”、“其他值”);
}
}
请注意,我还没有尝试上面的代码。如果它不起作用,那么也许您可以为每个实体类尝试一个单独的
CustomRepositoryImpl
实现 不完全确定问题出在哪里。JPAQuery
接口有一个Query.setHint(字符串hintName,对象值)
方法。如果您想要存储库方法的自定义实现(而不是自动生成的实现),只需使用该方法而不是@QueryHints
。类似地,对于实体图,使用javax.persistence.fetchgraph
和javax.persistence.loadgraph
hints@crizzisJPA查询接口确实有一个Query.setHint
方法,我可以在CustomItemRepositoryImpl.findItemById
方法中使用该方法。问题是:如何从注释(@QueryHints
和@EntityGraph
)中提取提示列表?为什么还要提取任何内容?@QueryHints
注释仅作为一种解决方法存在,因为当Spring为您生成实现时,您没有机会直接与EntityManager
交互并根据自己的喜好配置查询提示。编写自定义查询方法时,您负责实现,不需要任何注释。只需编写em.createXxxQuery(…).setHint(“name”,“value”).getResultList()
就像您编写@QueryHint(name=“name”,value=“value”)
@crizzis一样,您显然没有理解我的观点,因为我的示例不够清晰。请看我的更新答案。@crizzisItemRepository
可以有不同的查询提示,比如说,UserRepository
——最后一个扩展了CustomRepository
,谢谢你的回答。实际上,我并不期望“Spring会在中途神奇地介入并注入查询提示”。您可以查看org.springframework.data.querydsl.QuerydslPredicateExecutor
。这是一个片段存储库,这里的查询提示注释可以正常工作。我想获得类似的东西,而不必提供特殊的方法来检索每个特定存储库的提示映射。querydsldpredicateexecutor
可以工作,因为同样,您不是创建和执行查询的人(一个谓词
还不是JPA查询
),Spring实际上,我可以复制粘贴他们用来检索方法元数据的代码(org.springframework.data.jpa.repository.support.CrudMethodMetadata
)。它在工作,但它太重了。对于许多存储库,这可能有些过分。