有没有办法通过 QueryDSL 中的 Predicate API 急切地获取惰性关系?

2024-03-30

我正在使用QueryDslPredicateExecutor来自 Spring Data JPA 项目,我面临着急于获取惰性关系的需要。我知道我可以在 Repository 接口中使用本机 JPA-QL 查询,甚至可以使用 Query DSL 中的 JPAQLQuery,但我很好奇是否可以这样做,以便于构建满足未来需求的查询。


我遇到了类似的问题,在使用谓词和 QueryDslPredicateExecutor 时必须获取连接集合。

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

不要被这里的代码量吓倒,它实际上非常简单,您只需进行很少的更改即可在您的应用程序中使用它

这是自定义存储库的界面

@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));
}

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

感谢 Murali 的回复,我能够做到这一点:Spring Data JPA 和 Querydsl 使用 bean/构造函数投影获取列子集 https://stackoverflow.com/questions/18300465/spring-data-and-querydsl-to-fetch-subset-of-columns-using-bean-constructor-proje请看一下。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法通过 QueryDSL 中的 Predicate API 急切地获取惰性关系? 的相关文章

随机推荐

  • 将文件从 HDFS 复制到本地计算机

    我在尝试将文件从 HDFS 文件系统 下载 到本地系统时遇到问题 即使相反的操作没有问题 注意 文件存在于 HDFS 文件系统的指定路径上 这是一个代码片段 Configuration conf new Configuration conf
  • 如何在 Typescript 中使用 Cytoscape.js 的 UI 扩展?

    是否可以在 Typescript 中使用 Cytoscape UI 扩展 可以使用布局扩展 但是当我需要时https github com cytoscape cytoscape js cxtmenu https github com cy
  • 在散景 vbar 工具提示中显示高度

    我想制作一些简单数据的条形图 例如像这样的 pandas 数据框 Cats 4 Dogs 3 Mice 27 我想要一个工具提示 当鼠标悬停在栏上时显示如下内容 Name Cats Count 4 对于条形图 这适用于 hover tool
  • 在 Java 中通过引用传递数组

    在Java中可以将数组作为参数传递吗 int 5 result 我想传递对数组的引用 因为我想更改调用函数中的数组 语法是什么 private void demo int array new int 5 System out println
  • 无法部署firebase功能

    Node js 命令提示符只是忽略此函数 而其他函数正在部署 我也没有收到任何错误 var database admin database var postsRef database ref posts postsRef on child
  • PyInstaller - FileNotFoundError:没有这样的文件或目录:“”

    我看过很多关于这个完全相同的错误代码的帖子 但有许多不同的答案 但我仍然无法解决我的问题 我的帖子与所有其他帖子的不同之处在于我得到以下内容 317 INFO Building PKG because PKG 00 toc is non e
  • 使用 pyodbc 从 Python 应用程序将值插入 Access 2003 数据库

    我过去经常检查 stackoverflow 并且总是能够找到我一直在寻找的东西 但我似乎无法让这个工作 所以我问我的第一个问题 我并不是一个真正的程序员 但我在工作中提到过Python 现在我有一个Python项目 实际上 我已经把一切都弄
  • Spring Security 与 Struts 的集成

    我正在尝试在一个简单的应用程序中将 spring security 与 struts1 2 使用 LDAP 集成 我有 applicationContext security xml
  • ASP.NET MVC 5 和 Web API 2 .NET 要求

    我的主机提供商仅支持 NET 4 是否可以在 NET 4 计算机中运行 MVC 5 和 Web API 2 简短回答 不 您需要 NET 4 5 仅当添加依赖项时 剃须刀 v3 0 ASP NET 网页 v3 0
  • iPhone 在个人热点模式下不发送网络广播/组播

    根据最近的实证研究结果以及网络上的各种帖子 在启用了个人热点的 iPhone 上运行的应用程序似乎无法将广播和 或多播发送到个人热点的网络上 任何人都可以阐明这个问题的原因吗 应用程序 我有一个用跨平台 C 代码构建的 IOS 应用程序 它
  • 将图像添加到 Facebook 分享

    我正在尝试通过以下方式将图像添加到页面共享https developers facebook com docs plugins share button https developers facebook com docs plugins
  • 用于恢复保存后更改的宏

    我在网上找到了一个旧脚本来关闭文档而不保存更改 然后重新打开文档 Sub RevertFile wkname ActiveWorkbook Path ActiveWorkbook Name ActiveWorkbook Close Save
  • SQL Server while循环联合所有[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在尝试
  • SQL Server 日期时间过滤查询

    我在 SQL Server 中有这样的查询 SELECT Order Date SUM Profit FROM sample dbo superstore WHERE Order Date BETWEEN 2012 06 21 00 00
  • 获取Weblogic服务器上部署的所有应用程序的列表

    使用以下代码 我可以连接到 weblogic 服务器 现在我想获取服务器上部署的所有应用程序的列表 命令提示符下的 listapplications 列出了应用程序 但是当我执行terpreter exec listapplications
  • CXF 客户端安全

    我正在创建 Java Soap Web 服务的客户端 但无法弄清楚如何正确传递密码 这是我的 硬编码 密码示例 Test public void exploratorySecurityTest String username user St
  • WebClient Unicode - 哪种 UTF8?

    当我创建 WebClient 来使用一些 RESTful xml 时 我可以通过两种方式指定 unicode 编码 WebClient wc new WebClient wc Encoding Encoding UTF8 wc Encodi
  • 使用 CloudFront 部署在 S3 上的 VueJS 应用程序“指定的密钥不存在”

    我已经使用 Route53 部署了带有 S3 和 CloudFront 的 VueJS 应用程序 看起来一切都很顺利 我可以访问该网站https my domain com 我可以导航到我使用 Vue 路由器设置的不同路线 但是 当我尝试访
  • 在 Ionic 2 中使用图像资源的正确方法

    Ionic 2 中图像资源的最佳实践是什么 我有一堆 SVG 想用作非系统图标 我发现了一些关于使用 Gulp 的旧技巧 但似乎 Ionic 团队已决定将 Rollup 作为首选构建工具 到目前为止还没有相关文档 有人告诉我只需将它们添加到
  • 有没有办法通过 QueryDSL 中的 Predicate API 急切地获取惰性关系?

    我正在使用QueryDslPredicateExecutor来自 Spring Data JPA 项目 我面临着急于获取惰性关系的需要 我知道我可以在 Repository 接口中使用本机 JPA QL 查询 甚至可以使用 Query DS