【问题标题】:Nested objects in data projection in Hibernate, JPQL queryHibernate,JPQL查询中数据投影中的嵌套对象
【发布时间】:2020-07-23 15:41:23
【问题描述】:

我想创建投影。 DTO平坦时没有问题:

class Projection {
    String id;
    String fieldA;
    String fieldB;
    Projection(String id, String fieldA, String fieldB){
    ...
    }
}

那么查询将是:

SELECT new Projection(t.id, t.fieldA, t.fieldB) FROM Entity t WHERE t.id...

但我无法为该投影创建查询:

class Projection {
        String id;
        NestedObject nested;
        Projection(String id, NestedObject nested){
        ...
        }
 }
class NestedObject {
    String fieldA;
    String fieldB;
    NestedObject(String fieldA, String fieldB){
    ...
    }
}

我试过了:

SELECT new Projection(t.id, (SELECT new NestedObject(n.fieldA, n.fieldB) FROM Entity n)) FROM Entity t WHERE t.id...

但不起作用。

两个问题:

  1. 有可能吗?
  2. 如果 1 的答案是肯定的,这个查询应该是什么样子?

【问题讨论】:

    标签: hibernate jpql projection


    【解决方案1】:

    您为什么不在Project 中创建一个构造函数并使用您的原始查询,除非您的问题缺少某些细节?

        class Projection {
          String id;
          NestedObject nested;
        
          Projection(String id, String fieldA, String fieldB){
            this.id = id
            nested = new NestedObject(filedA, fieldB);
          }
        }
    

    【讨论】:

    • 是的,这是解决方法。但我想知道我所要求的解决方案是否可行。
    • 如果我们有原生查询怎么办
    【解决方案2】:

    这是不可能的,因为 JPQL 不需要嵌套构造函数调用,并且没有提供者支持该 AFAIK。

    话虽如此,这是Blaze-Persistence Entity Views 的完美用例。

    Blaze-Persistence 是基于 JPA 的查询构建器,它支持 JPA 模型之上的许多高级 DBMS 功能。我在它之上创建了实体视图,以允许在 JPA 模型和自定义接口定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您以您喜欢的方式定义目标结构,并通过 JPQL 表达式将属性(getter)映射到实体模型。由于属性名称用作默认映射,因此您通常不需要显式映射,因为 80% 的用例是拥有作为实体模型子集的 DTO。

    假设你有一个这样的实体模型

    @Entity
    public class User {
        @Id
        Integer id;
        String role;
        String username;
        @ManyToOne
        Tenant tenant;
    }
    
    @Entity
    public class Tenant {
        @Id
        Integer id;
        String name;
        String address;
    }
    

    模型的 DTO 映射可能如下所示简单

    @EntityView(User.class)
    interface UserDto {
        Integer getId();
        String getUsername();
        TenantDto getTenant();
    }
    @EntityView(Tenant.class)
    interface TenantDto {
        Integer getId();
        String getName();
    }
    

    查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。

    UserDto dto = entityViewManager.find(entityManager, UserDto.class, id);

    但是 Spring Data 集成允许您几乎像 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

    它只会获取您告诉它获取的映射

    【讨论】:

    • 有趣的库。不错的选择。感谢您的回答。所以这是不可能的。然后我会采取@Kavithakaran Kanapathippillai 平面解决方案。
    • 这个库的性能怎么样?
    • 性能是最好的。它在启动时计算很多东西,以便在运行时尽可能高效。性能更好的主要原因是底层查询只会为实际需要的部分添加选择项和连接。
    猜你喜欢
    • 2019-11-04
    • 1970-01-01
    • 2018-07-18
    • 1970-01-01
    • 2021-07-16
    • 2021-01-28
    • 2014-07-06
    • 1970-01-01
    • 2018-02-20
    相关资源
    最近更新 更多