【问题标题】:JPQL: Receiving a Collection in a Constructor ExpressionJPQL:在构造函数表达式中接收集合
【发布时间】:2011-08-25 07:11:34
【问题描述】:

我正在使用 JPQL,并希望在构造函数表达式中接收一些普通参数和一个集合,以直接创建 DTO 对象。但是如果Collection是空的,我总是会报错,因为他没有找到正确的构造函数:

DTO 类如下所示:

public class DTO {
    private long id;
    private String name;
    private Collection<Child> children;

    public DTO (long id, String name, Collection<Child> children){
    this.id = id;
    this.name = name;
    this.children= children;
    }
}

子类:

public class Child {
    private String name;
    private int age;
}

现在构造函数表达式如下所示:

return (List<DTO>) getEm().createQuery("SELECT DISTINCT NEW de.DTO(p.id, p.name, p.childs) 
                                          FROM Parent p").getResultList();

当前的问题是,如果 Collection p.childs 为空,它说它没有找到正确的构造函数,它需要 (long, String, Child) 而不是 (long, String, Collection)。

您有任何解决方案,还是根本不可能在构造函数表达式中使用集合?

还有一件事:如果我轻松地创建两个构造函数(...、Collection childs AND ...、Child childs),我不会得到任何结果,但也没有错误...在我看来并不是很满意:- /

【问题讨论】:

  • 我认为您忘记发布您的Parent 课程。 child 的复数形式也是children
  • 您是否尝试过在查询中添加条件 - "WHERE p.childs IS NOT EMPTY AND SIZE(p.childs) 0"
  • 我也在寻找类似的东西,我能找到的最接近你所问的东西(不依赖额外的库)是@VladMihalcea 的标题为How to fetch a one-to-many DTO projection with JPA and Hibernate 的帖子 -这是我对Q46681780 的评论的副本,因为它看起来非常接近这个评论。如果这被视为垃圾邮件或其他内容,我们深表歉意......

标签: java jpa constructor expression jpql


【解决方案1】:

JPA 规范(至少 2.0、2.1 和 2.2 版)不允许在构造函数表达式中使用集合作为参数。 4.8 节定义了一个这样的构造函数表达式:

constructor_expression ::=
        NEW constructor_name ( constructor_item {, constructor_item}* )
constructor_item ::=
        single_valued_path_expression |
        scalar_expression |
        aggregate_expression |
        identification_variable

single_valued_path_expression 听起来像 - 一个指向某种标量的属性表达式(例如 p.id),scalar_expression 也是一个指向标量的表达式,aggregate_expression 是像sum 这样的函数的应用,它将多值表达式简化为标量表达式,identification_variable 是对您正在查询的类型的引用。没有一个可以收藏价值。

所以,如果您的 JPA 提供程序允许您在构造函数表达式中使用集合值参数,那是因为它超出了规范。这是非常好的,但不是你必须依赖的东西!

【讨论】:

  • 嗨,汤姆·安德森,非常感谢您提供这些信息。我只是使用 Eclipse Link,所以我想,不使用 Hibernate 或其他东西,它也作用于更高层,我不会成功。 @评论:是的,对,我忘记了父类,但我也只有一个 id、一个名字和一个有或没有孩子的 Collection。所以像 IS NOT EMPTY 这样的条件不符合我的目标,我也需要没有孩子的父母。也感谢您的帮助。
  • 在 JPA 2.1 中相同,参见第 4.14 章 BNF,第 211 页。
【解决方案2】:

试试,

public DTO (long id, String name, Object children)

【讨论】:

    【解决方案3】:

    我遇到了类似的问题,并按照 James 的建议在 DTO 构造函数中尝试了“Object”,但是传入了一个子对象,它似乎只是第一个子对象,而不是预期的子对象列表/数组。

    我最终得到了一个“正常”查询,在 for 循环中创建了所有 DTO。

    TypedQuery<Parent> query = em.createQuery("SELECT p FROM Parent p", Parent class);
            List<Parent> list = query.getResultList();
            List<DTO> result = new ArrayList<>();
            for (Parent p : list)
            {
                DTO dto = new DTO();
                //set dto props and fill collection
                result.add(obj);
            }
            return result;
    

    【讨论】:

      【解决方案4】:

      这不可能像其他人已经回答的那样开箱即用,但我认为这是 Blaze-Persistence Entity Views 的完美用例。

      我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

      使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:

      @EntityView(Parent.class)
      public interface ParentDto {
          @IdMapping
          Long getId();
          String getName();
          Set<ChildDto> getChildren();
      
          @EntityView(Child.class)
          interface ChildDto {
              @IdMapping
              Long getId();
              String getName();
              int getAge();
          }
      }
      

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

      ParentDto a = entityViewManager.find(entityManager, ParentDto.class, id);

      Spring Data 集成让您可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

      Page<ParentDto> findAll(Pageable pageable);
      

      最好的部分是,它只会获取实际需要的状态!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-16
        • 2018-09-03
        • 2012-08-29
        • 1970-01-01
        • 2017-08-21
        • 1970-01-01
        • 2018-12-27
        • 1970-01-01
        相关资源
        最近更新 更多