当前位置: 首页 > 知识库问答 >
问题:

Spring Data JPA:创建规范查询提取联接

司徒炎彬
2023-03-14

TL;DR:如何使用Spring Data JPA中的规范复制JPQL Join-Fetch操作?

@Entity
public class Gene {

    @Id 
    @Column(name="entrez_gene_id")
    privateLong id;

    @Column(name="gene_symbol")
    private String symbol;

    @Column(name="species")
    private String species;

    @OneToMany(mappedBy="gene", fetch=FetchType.EAGER) 
    private Set<GeneSymbolAlias> aliases;

    @OneToMany(mappedBy="gene", fetch=FetchType.EAGER) 
    private Set<GeneAttributes> attributes;

    // etc...

}

@Entity
public class GeneSymbolAlias {

    @Id 
    @Column(name = "alias_id")
    private Long id;

    @Column(name="gene_symbol")
    private String symbol;

    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumn(name="entrez_gene_id")
    private Gene gene;

    // etc...

}
@Service
public class GeneService {

    @Autowired private GeneRepository repository;
    @Autowired private GeneSpecificationBuilder builder;

    public List<Gene> findGenes(Map<String,Object> params){
        return repository.findAll(builder.getSpecifications(params));
    }

    //etc...

}

@Component
public class GeneSpecificationBuilder {

    public Specifications<Gene> getSpecifications(Map<String,Object> params){
        Specifications<Gene> = null;
        for (Map.Entry param: params.entrySet()){
            Specification<Gene> specification = null;
            if (param.getKey().equals("symbol")){
                specification = symbolEquals((String) param.getValue());
            } else if (param.getKey().equals("species")){
                specification = speciesEquals((String) param.getValue());
            } //etc
            if (specification != null){
               if (specifications == null){
                   specifications = Specifications.where(specification);
               } else {
                   specifications.and(specification);
               }
            }
        } 
        return specifications;
    }

    private Specification<Gene> symbolEquals(String symbol){
        return new Specification<Gene>(){
            @Override public Predicate toPredicate(Root<Gene> root, CriteriaQuery<?> query, CriteriaBuilder builder){
                return builder.equal(root.get("symbol"), symbol);
            }
        };
    }

    // etc...

}

在本例中,每次我要检索gene记录时,我还想要它关联的geneAttributegeneSymbolAlias记录。这一切都按预期工作,对单个gene的请求将引发3个查询:genegeneAttributegeneSymbolAlias表各一个查询。

问题是,没有理由需要运行3个查询来获得具有嵌入属性和别名的单个gene实体。这可以在普通SQL中完成,也可以在我的Spring Data JPA存储库中使用JPQL查询完成:

@Query(value = "select g from Gene g left join fetch g.attributes join fetch g.aliases where g.symbol = ?1 order by g.entrezGeneId")
List<Gene> findBySymbol(String symbol);

如何使用规范复制此取数策略?我在这里发现了这个问题,但它似乎只是让懒惰的获取变成急切的获取。

共有1个答案

魏凡
2023-03-14

规格类别:

public class MatchAllWithSymbol extends Specification<Gene> {
    private String symbol;

    public CustomSpec (String symbol) {
    this.symbol = symbol;
    }

    @Override
    public Predicate toPredicate(Root<Gene> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

        //This part allow to use this specification in pageable queries
        //but you must be aware that the results will be paged in   
        //application memory!
        Class clazz = query.getResultType();
        if (clazz.equals(Long.class) || clazz.equals(long.class))
            return null;

        //building the desired query
        root.fetch("aliases", JoinType.LEFT);
        root.fetch("attributes", JoinType.LEFT);
        query.distinct(true);        
        query.orderBy(cb.asc(root.get("entrezGeneId")));
        return cb.equal(root.get("symbol"), symbol);
    }
}

用法:

    List<Gene> list = GeneRepository.findAll(new MatchAllWithSymbol("Symbol"));
 类似资料:
  • 有一个使用属性表达式的查询:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-方法。查询属性表达式: 试图通过规范执行查询: 我得到了一个错误: 我做错了什么或忘记添加了什么? 查询:按教师姓名显示所有学生 基地实体: 实体教师: 实体学生: 实体教室: 实体教室:

  • 我有下面的查询,其中两个表连接在非主列上。该表连接到一个公用列上。 用户详细信息 如何在JPA规范中实现相同的查询

  • jpaQuery.from(tableA,tableb)。(如何编写以下条件)。id=表格b。id() 如何使用查询dsl编写左向外连接?? 这是编写eq连接的示例代码 JPA query query = new JPA query(em); Q表A = Q表A.QTableB 表 B = QTableB 表 B query.from(tableA, tableB). where(tableA.i

  • 以下示例将演示如何在DBUtils的帮助下,使用语句来创建记录。 我们将在表中插入一条记录。 语法 其中, insertQuery − Insert query having placeholders. queryRunner − QueryRunner object to insert employee object in database. 为了理解上述与DBUtils相关的概念,我们编写一个

  • 主要内容:创建一个更新查询,创建一个删除查询,创建一个建表查询在本章中让我们来了解如何创建查询。 创建一个更新查询 可以使用更新查询更改表中的数据,并且可以使用更新查询来输入条件以指定应更新哪些行。 在执行更新之前,更新查询提供了一个查看更新数据的机会。 让我们再次转到“创建”选项卡,然后单击“查询设计”。 在“表”选项卡的“显示表”对话框中,双击表,然后关闭对话框。 在“设计”选项卡的“查询类型”组中,单击“更新”并双击要更新值的字段。假设要将员工编号为: