gpt4 book ai didi

java - Spring 数据 JPA : Creating Specification Query Fetch Joins

转载 作者:IT老高 更新时间:2023-10-28 13:47:12 25 4
gpt4 key购买 nike

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

我正在尝试构建一个类,该类将使用 Spring Data JPA 处理 JPA 实体的动态查询构建。为此,我定义了许多创建 Predicate 的方法。对象(如 Spring Data JPA docs 和其他地方所建议的),然后在提交适当的查询参数时链接它们。我的一些实体与有助于描述它们的其他实体具有一对多的关系,这些实体在查询时被急切地获取并合并为用于创建 DTO 的集合或映射。一个简化的例子:

@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...

}

查询字符串参数从 Controller 传递类到Service类作为键值对,在那里它们被处理并组装成 Predicates :

@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 个查询:每个到 Gene , GeneAttribute , 和 GeneSymbolAlias表。

问题在于没有理由需要运行 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);

如何使用规范复制此获取策略?我找到了 this question here ,但它似乎只会使惰性获取变为急切获取。

最佳答案

规范类:

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"));

关于java - Spring 数据 JPA : Creating Specification Query Fetch Joins,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29348742/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com