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

有没有办法通过QueryDSL中的谓词API获取惰性关系?

劳法
2023-03-14

我正在使用Spring Data JPA项目中的QueryDslPredicateExecutor,并且我面临着急于获取惰性关系的需求。我知道我可以在存储库界面中使用本机 JPA-QL 查询,甚至可以使用查询 DSL 中的 JPAQLQuery,但我很好奇这是否可能,以便于为未来需求构建查询。

共有2个答案

闾丘选
2023-03-14

Spring data引入了JPA实体图支持。注意,is目前不支持通过嵌入式id遍历的图。

暴英达
2023-03-14

我有一个类似的问题,我必须在使用谓词和QueryDslPredicateExec的同时获取加入集合。

我所做的是创建一个自定义存储库实现来添加一个允许我定义应该获取的实体的方法。

不要被这里的代码量吓倒,它实际上非常简单,您需要做很少的更改才能在您的应用程序上使用它

这是自定义存储库的界面

@NoRepositoryBean
public interface JoinFetchCapableRepository<T, ID extends Serializable> extends     JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {

    Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors);
}

连接描述器

public class JoinDescriptor {
    public final EntityPath path;
    public final JoinType type;

    private JoinDescriptor(EntityPath path, JoinType type) {
        this.path = path;
        this.type = type;
    }

    public static JoinDescriptor innerJoin(EntityPath path) {
        return new JoinDescriptor(path, JoinType.INNERJOIN);
    }

    public static JoinDescriptor join(EntityPath path) {
        return new JoinDescriptor(path, JoinType.JOIN);
    }

    public static JoinDescriptor leftJoin(EntityPath path) {
        return new JoinDescriptor(path, JoinType.LEFTJOIN);
    }

    public static JoinDescriptor rightJoin(EntityPath path) {
        return new JoinDescriptor(path, JoinType.RIGHTJOIN);
    }

    public static JoinDescriptor fullJoin(EntityPath path) {
        return new JoinDescriptor(path, JoinType.FULLJOIN);
    }
}

自定义存储库的实现

public class JoinFetchCapableRepositoryImpl <T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> implements JoinFetchCapableRepository<T, ID> {

    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;

    private final EntityPath<T> path;
    private final PathBuilder<T> builder;
    private final Querydsl querydsl;

    public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
    }

    public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
        super(entityInformation, entityManager, resolver);
        this.path = resolver.createPath(entityInformation.getJavaType());
        this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
        this.querydsl = new Querydsl(entityManager, builder);
    }

    @Override
    public Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors) {
        JPQLQuery countQuery = createQuery(predicate);
        JPQLQuery query = querydsl.applyPagination(pageable, createFetchQuery(predicate, joinDescriptors));

        Long total = countQuery.count();
        List<T> content = total > pageable.getOffset() ? query.list(path) : Collections.<T> emptyList();

        return new PageImpl<>(content, pageable, total);
    }

    protected JPQLQuery createFetchQuery(Predicate predicate, JoinDescriptor... joinDescriptors) {
        JPQLQuery query = querydsl.createQuery(path);
        for(JoinDescriptor joinDescriptor: joinDescriptors)
            join(joinDescriptor, query);
        return query.where(predicate);
    }

    private JPQLQuery join(JoinDescriptor joinDescriptor, JPQLQuery query) {
        switch(joinDescriptor.type) {
            case DEFAULT:
                throw new IllegalArgumentException("cross join not supported");
            case INNERJOIN:
                query.innerJoin(joinDescriptor.path);
                break;
            case JOIN:
                query.join(joinDescriptor.path);
                break;
            case LEFTJOIN:
                query.leftJoin(joinDescriptor.path);
                break;
            case RIGHTJOIN:
                query.rightJoin(joinDescriptor.path);
                break;
            case FULLJOIN:
                query.fullJoin(joinDescriptor.path);
                break;
        }
        return query.fetch();
    }
}

工厂创建自定义存储库,替换默认的 QueryDslJpaRepository

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

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {

        return new JoinFetchCapableQueryDslJpaRepositoryFactory(entityManager);
    }
    private static class JoinFetchCapableQueryDslJpaRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

        private EntityManager entityManager;

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

        protected Object getTargetRepository(RepositoryMetadata metadata) {
            return new JoinFetchCapableRepositoryImpl<>(getEntityInformation(metadata.getDomainType()), entityManager);
        }

        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return JoinFetchCapableRepository.class;
        }
    }
}

最后一步是更改jpa配置,使其使用此工厂而不是默认工厂:

<jpa:repositories base-package="com.mycompany.repository"
                      entity-manager-factory-ref="entityManagerFactory"
                      factory-class="com.mycompany.utils.spring.data.JoinFetchCapableQueryDslJpaRepositoryFactoryBean" />

然后,您可以像这样从服务层使用它:

public Page<ETicket> list(ETicketSearch eTicket, Pageable pageable) {
    return eticketRepository.findAll(like(eTicket), pageable, JoinDescriptor.leftJoin(QETicket.eTicket.order));
}

通过使用Join描述符,您将能够根据您的服务需求指定要加入的内容。

我能够做到这一点要归功于Murali在这里的响应:Spring Data JPA和Querydsl使用bean/构造函数投影获取列子集。请看看。

 类似资料:
  • 我在应用程序中使用Querydsl来大大改进查询数据库的代码。但是,我有一个来自外部服务的JPA谓词(javax.persistence.criteria.Predicate)。我想混合使用Querydsl和外部谓词创建的查询。例如: 另一个解决方案是将Querydsl谓词转换为JPA谓词: 有可能吗?如果是,我如何做到这一点?如果没有,是否有其他混合谓词的解决方案(比如将两者转换为SQL字符串并

  • 很抱歉没有提供实际的代码,我的情况完全符合jackson中的问题--不要序列化惰性对象。由于这个问题没有解决方案,所以我强调了这个问题,以确保是否有解决方案,或者在本例中使用什么方法,而不是使用Jackson以JSON格式作为响应发送给对象。 谢谢

  • 问题内容: 即时消息插件可以接收IM消息,例如“ 在10秒钟内构建XYZ”,并将作业设置为在10秒内运行。它通过Java API来调度Job [0]。 我想知道是否可以通过REST API [1] 传递一些魔术参数,使我能够以相同的方式“延迟”作业? 谢谢。 [0] - https://github.com/jenkinsci/instant-messaging- plugin/blob/mast

  • 在web上,我只找到了一种停止迭代方法的方法。通过使用limit()函数。但这会迭代一个具体的循环数。我想用它来停止一个谓词。 有没有办法用Streams做到这一点? 更新1:使用Java 8

  • 我用Java编写了一个程序,我有以下问题: 在课程的后期,我再次需要这些学生。我可以这样做: 但是我没有学生的人数。有没有办法让他们的名字,这是在类学生?

  • 我使用查询DSL生成实体EntitySerializer,以便使用QueryDSL(与SpringData集成)查询JPA实体。