Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring数据JPA:创建规范查询获取连接_Java_Spring_Jpa_Spring Data Jpa_Criteria Api - Fatal编程技术网

Java Spring数据JPA:创建规范查询获取连接

Java Spring数据JPA:创建规范查询获取连接,java,spring,jpa,spring-data-jpa,criteria-api,Java,Spring,Jpa,Spring Data Jpa,Criteria Api,TL;DR:如何使用SpringDataJPA中的规范复制JPQL连接获取操作 我正在尝试构建一个类,该类将使用SpringDataJPA为JPA实体处理动态查询构建。为此,我定义了许多方法来创建谓词对象,如在和其他地方建议的,然后在提交适当的查询参数时将它们链接起来。我的一些实体与帮助描述它们的其他实体有一对多的关系,当查询这些实体并合并到集合或映射以创建数据时,它们会被急切地获取。一个简化的例子: @Entity public class Gene { @Id @Colu

TL;DR:如何使用SpringDataJPA中的规范复制JPQL连接获取操作

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

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

}
在本例中,每当我想要检索一个基因记录时,我还想要它的相关GeneAttribute和GeneSymbolAlias记录。这一切都按预期进行,对单个基因的请求将引发3个查询:分别对Gene、GeneAttribute和GeneSymbolAlias表进行查询

问题是,没有理由需要运行3个查询来获得具有嵌入属性和别名的单个基因实体。这可以在纯SQL中完成,也可以通过我的Spring数据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);
如何使用规范复制此抓取策略?我找到了,但它似乎只会将懒惰的抓取转变为急切的抓取。

规范类:

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

您可以在创建规范时指定联接获取,但由于可分页方法也将使用相同的规范 与findAllSpecification var1一样,Pageable var2和count查询也会因为join fetch而抱怨。因此,为了处理这个问题,我们可以检查CriteriaQuery的resultType,并且仅当它不是count查询的长结果类型时才应用join。见以下代码:

    public static Specification<Item> findByCustomer(Customer customer) {
    return (root, criteriaQuery, criteriaBuilder) -> {
        /*
            Join fetch should be applied only for query to fetch the "data", not for "count" query to do pagination.
            Handled this by checking the criteriaQuery.getResultType(), if it's long that means query is
            for count so not appending join fetch else append it.
         */
        if (Long.class != criteriaQuery.getResultType()) {
            root.fetch(Person_.itemInfo.getName(), JoinType.LEFT);
        }
        return criteriaBuilder.equal(root.get(Person_.customer), customer);
    };
}

您是否尝试使用root.fetch-inside-toPredicate?类似于root.fetchattributes,JoinType。LEFT@PredragMaric:这将急切地获取属性,但仍需要额外的查询。我希望所有回迁都是单个查询的一部分。是的,但另一个别名回迁应该可以做到:root.fetchalias,JoinType.left我以前尝试过这一点,正如我链接的问题中所建议的,但它没有达到预期的结果。问题不在于一个规范查询无法获取链接的实体,问题在于一个规范查询需要3个SQL查询才能获取这些实体,这是完全不必要的。我没有全部获取?你到底想要什么,你需要一个基因实体列表,通过编写规范来设置alises和attribute?如果你想要一个带有规范的基因列表,那么我可以给你合适的解决方案?关于如何使规范与SDJPA可分页查询一起工作的好技巧+1.它可以工作,但问题是hibernate在内存中进行分页,在控制台中,我看到此消息“HH000104:firstResult/maxResults指定了collection fetch;在内存中应用!',我试图用fetchjoin和entitygraph来解决这个问题,但我没有找到一个完美的解决方案。
    public static Specification<Item> findByCustomer(Customer customer) {
    return (root, criteriaQuery, criteriaBuilder) -> {
        /*
            Join fetch should be applied only for query to fetch the "data", not for "count" query to do pagination.
            Handled this by checking the criteriaQuery.getResultType(), if it's long that means query is
            for count so not appending join fetch else append it.
         */
        if (Long.class != criteriaQuery.getResultType()) {
            root.fetch(Person_.itemInfo.getName(), JoinType.LEFT);
        }
        return criteriaBuilder.equal(root.get(Person_.customer), customer);
    };
}