我正在使用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)我没有得到任何结果,但也没有错误......在我看来并不是很满意: - /
答案 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_expression
是sum
这样的函数的应用,它将多值表达式减少为标量值,而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);
最好的部分是,它只会获取实际需要的状态!