Java 使用片段的Spring数据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

从Spring5开始,我们可以选择使用多个片段存储库来丰富我们的JPA存储库

机制非常简单:声明然后实现一个接口

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
实现

不完全确定问题出在哪里。JPA
Query
接口有一个
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一样,您显然没有理解我的观点,因为我的示例不够清晰。请看我的更新答案。@crizzis
ItemRepository
可以有不同的查询提示,比如说,
UserRepository
——最后一个扩展了
CustomRepository
,谢谢你的回答。实际上,我并不期望“Spring会在中途神奇地介入并注入查询提示”。您可以查看
org.springframework.data.querydsl.QuerydslPredicateExecutor
。这是一个片段存储库,这里的查询提示注释可以正常工作。我想获得类似的东西,而不必提供特殊的方法来检索每个特定存储库的提示映射。
querydsldpredicateexecutor
可以工作,因为同样,您不是创建和执行
查询的人(一个
谓词
还不是JPA
查询
),Spring实际上,我可以复制粘贴他们用来检索方法元数据的代码(
org.springframework.data.jpa.repository.support.CrudMethodMetadata
)。它在工作,但它太重了。对于许多存储库,这可能有些过分。