JPQL:在构造函数表达式中接收集合

时间:2011-05-13 22:32:28

标签: java jpa constructor expression jpql

我正在使用JPQL并希望在Constructor Expression中接收一些常规参数和集合以直接创建DTO对象。但是如果Collection是空的,我总是会收到错误,因为他找不到合适的构造函数:

DTO-Class看起来如下:

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?

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

4 个答案:

答案 0 :(得分:11)

这不是答案。

据我所知,JPA 2.0规范不允许在构造函数表达式中使用集合作为参数。 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_expressionsum这样的函数的应用,它将多值表达式减少为标量值,而identification_variable是对要查询的类型的引用。这些都不是收藏价值的。假设我已经阅读了规范。

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

答案 1 :(得分:3)

尝试,

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

答案 2 :(得分:2)

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

我最终选择了#34;正常&#34;查询在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;

答案 3 :(得分:0)

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

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

您的用例的 DTO 模型可能如下所示,其中包含 Blaze-Persistence Entity-Views:

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

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