Spring Data JPA + JpaSpecificationExecutor + EntityGraph [英] Spring Data JPA + JpaSpecificationExecutor + EntityGraph

查看:692
本文介绍了Spring Data JPA + JpaSpecificationExecutor + EntityGraph的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(使用Spring Data JPA)我有两个实体 Parent & Child ,它们之间具有OneToMany / ManyToOne双向关系。我添加了一个 @NamedEntityGraph 到父实体,如下所示:

(Using Spring Data JPA) I have two entities Parent& Child with a OneToMany/ManyToOne bi-directional relationship between them. I add a @NamedEntityGraph to the parent entity like so:

@Entity
@NamedEntityGraph(name = "Parent.Offspring", attributeNodes = @NamedAttributeNodes("children"))
public class Parent{
//blah blah blah

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
Set<Child> children;

//blah blah blah
}

请注意父母的孩子的获取类型是LAZY。这是故意的。当我查询个别父母时,我并不总是希望加载孩子。通常我可以使用我的命名实体图来按需加载孩子,可以这么说。但是......

Notice that the fetch type for the Parent's children is LAZY. This is on purpose. I don't always want to eager load the children when I'm querying an individual parent. Normally I could use my named entity graph to eager load the children on-demand, so to speak. But.....

我有一个特定的情况,我想查询一个或多个父母,并急切地加载他们的孩子。除此之外,我还需要能够以编程方式构建此查询。 Spring Data提供 JpaSpecificationExecutor ,允许一个构建动态查询,但在这种特定情况下,我无法弄清楚如何将它与实体图一起用于急切加载子项。这有可能吗?有没有其他方法可以使用规范急切加载到多个实体?

There is a specific situation where I'd like to query for one or more parents AND eager load their children. In addition to this I need to be able to build this query programmatically. Spring Data provides the JpaSpecificationExecutor which allows one to build dynamic queries, but I can't figure out how to use it in conjunction with entity graphs for eager loading children in this specific case. Is this even possible? Is there some other way to eager load 'toMany entities using specifications?

推荐答案

解决方案是创建一个实现的自定义存储库接口这些功能:

The solution is to create a custom repository interface that implements these features:

@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {

    List<T> findAll(Specification<T> spec, EntityGraphType entityGraphType, String entityGraphName);
    Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraphType entityGraphType, String entityGraphName);
    List<T> findAll(Specification<T> spec, Sort sort, EntityGraphType entityGraphType, String entityGraphName);
    T findOne(Specification<T> spec, EntityGraphType entityGraphType, String entityGraphName);

}

同时创建一个实现:

@NoRepositoryBean
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {

    private EntityManager em;

    public CustomRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
    }

    @Override
    public List<T> findAll(Specification<T> spec, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, (Sort) null);
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return query.getResultList();
    }

    @Override
    public Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, pageable.getSort());
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return readPage(query, pageable, spec);
    }

    @Override
    public List<T> findAll(Specification<T> spec, Sort sort, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, sort);
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return query.getResultList();
    }

    @Override
    public T findOne(Specification<T> spec, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, (Sort) null);
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return query.getSingleResult();
    }
}

创建工厂:

public class CustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new CustomRepositoryFactory(entityManager);
    }

    private static class CustomRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

        private EntityManager entityManager;

        public CustomRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }

        protected Object getTargetRepository(RepositoryMetadata metadata) {
            return new CustomRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
        }

        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            // The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
            //to check for QueryDslJpaRepository's which is out of scope.
            return CustomRepository.class;
        }
    }

}

并改变新bean的默认存储库工厂bean,例如在spring boot中将其添加到配置中:

And change the default repository factory bean to the new bean, e.g. in spring boot add this to the configuration:

@EnableJpaRepositories(
    basePackages = {"your.package"},
    repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class
)

有关自定义存储库的更多信息: http ://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories

For more info about custom repositories: http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories

这篇关于Spring Data JPA + JpaSpecificationExecutor + EntityGraph的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆