我想用HQL创建新对象,所以我尝试发出以下查询:
String hql = "SELECT new com.pizzaboy.dto.OrderDTO(o.adress, o.orderDate, dt, r, d)"
+ " FROM Order o JOIN o.user u "
+ " JOIN FETCH o.deliveryType dt"
+ " JOIN FETCH o.restaurant r "
+ " JOIN FETCH o.dishes d"
//+ " JOIN FETCH d.dishType disht "
+ " WHERE u.id=:id";
<小时/> 它给出了以下错误,好像“o.dishes”不是List或Set:
org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.pizzaboy.dto.OrderDTO]. Expected arguments are: com.pizzaboy.pojo.Adress, java.util.Date, com.pizzaboy.pojo.DeliveryType, com.pizzaboy.pojo.Restaurant, com.pizzaboy.pojo.Dish [SELECT new com.pizzaboy.dto.OrderDTO(o.adress, o.orderDate, dt, r, elements(d)) FROM com.pizzaboy.pojo.Order o JOIN o.user u JOIN FETCH o.deliveryType dt JOIN FETCH o.restaurant r JOIN FETCH o.dishes d WHERE u.id=:id]
然而,确实是Set:
@Entity
@Table(name = "orders", catalog = "PIZZABOY")
public class Order implements java.io.Serializable {
private Integer id;
private Adress adress;
private DeliveryType deliveryType;
private Payment payment;
private Restaurant restaurant;
private User user;
private Date orderDate;
private Set<Dish> dishes = new HashSet<Dish>(0);
...
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
public Set<Dish> getDishes() {
return this.dishes;
}
public void setDishes(Set<Dish> dishes) {
this.dishes = dishes;
}
为什么我会收到此错误以及如何解决?
PS OderDTO构造函数
public OrderDTO(Adress adress, Date orderDate, DeliveryType deliveryType, Restaurant restaurant,
List<Dish> dishes) {
答案 0 :(得分:1)
您无法以这种方式返回集合:当您执行HQL / JPQL时,您处于对象与关系世界之间的跨领域,其中结果是面向对象的,但计算发生在面向表的空间上
为什么不简单?
String hql = "SELECT new com.pizzaboy.dto.OrderDTO(o)"
+ " FROM Order o JOIN o.user u "
+ " JOIN FETCH o.deliveryType dt"
+ " JOIN FETCH o.restaurant r "
+ " JOIN FETCH o.dishes d"
+ " WHERE u.id=:id";
和
public OrderDTO(Order order)
{
this.adress = order.getAddress();
this.deliveryType = order.getDeliveryType();
this.restaurant = order.getRestaurant();
this.dishes = new ArrayList<>(order.getDishes());
}
Hiberante将注意以ORM的形式开展工作,加载相关实体/实体集合并将它们放在正确的位置(因为您指定了 FETCH
,这可能可能只用一个SQL查询发生。)
似乎不可能使用内联FETCH
急切地加载集合,原因是存在技术限制(可能它应该被视为一个错误,类似于您无法加入fecth倍数的事实单个查询中的bags
。
所以你剩下2个选择:
从查询中删除FETCH
并手动初始化延迟属性:
SELECT new com.pizzaboy.dto.OrderDTO(o)
FROM Order o
JOIN o.user u
WHERE u.id=:id
和
public OrderDTO(Order order)
{
Hibernate.initialize(order.getAddress());
this.adress = order.getAddress();
Hibernate.initialize(order.getDeliveryType());
this.deliveryType = order.getDeliveryType();
Hibernate.initialize(order.getRestaurant());
this.restaurant = order.getRestaurant();
Hibernate.initialize(order.getDishes());
this.dishes = new ArrayList<>(order.getDishes());
}
这会让您面临N + 1问题:使用batch-fetch
可以避免
使用实体图/获取配置文件:
SELECT new com.pizzaboy.dto.OrderDTO(o)
FROM Order o
JOIN o.user u
WHERE u.id=:id
EntityGraph<Order> graph = entityManager.createEntityGraph(Order.class);
graph.addAttributeNodes(Order_.deliveryType, Order_.restaurant);
graph.addSubgraph(Order_.dishes);
entityManager.createQuery(hql)
.setHint("javax.persistence.fetchgraph", graph)
.setParameter("id", userId)
.getResultList();
由于我从未使用具有自定义对象选择的实体图,因此可能会遇到与使用内联联接提取相同的错误
但是,我认为返回DTO
与相关Entity
几乎相同的DETACHED
没什么用处:只返回实体本身(可能是你想要的)它在 e.g.: DateTime.ParseExact("12/02/21 10:56:09", "yy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture
).ToString("MMM. dd, yyyy HH:mm:ss")
州。)
显然,当你必须处理由不同实体和/或实体属性和/或函数计算(如count,sum,a + b,...等)组成的东西时,这不适用