2016-09-13 44 views
1

我想創建一個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」不列出或設置:

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] 

但是,它被設置,的確是:

@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

請,發佈OrderDTO構造函數 –

+0

@JoeTaras問題更新 – 0x6B6F77616C74

+0

只是爲了清楚起見,您能否在兩個對象上使用Set(或List)?目前您正在獲取一個Set並嘗試將它用作List。 –

回答

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層的替代品:

  1. 從查詢中刪除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

  2. 使用實體圖/擷取檔案:

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

    因爲我從來沒有使用過實體的圖形自定義對象選擇,如使用內聯連接抓取,這可能擊中了同樣的bug

但是,我沒有看到太多用於返回DTO這是幾乎相同的東西作爲相關的Entity:只是返回enti ty本身(可能你想要它在DETACHED狀態)。
很明顯,當你必須處理的事情是不同的實體和/或實體性和/或功能類似的計算數量,金額,A + B的組合物,這並不適用...

+0

它給了我一個例外:「查詢指定的連接抓取,但獲取的關聯的所有者不在選擇列表中。」 – 0x6B6F77616C74

+0

「但是,在返回與相關實體幾乎相同的DTO方面,我看不到太多用處:只返回實體本身」。我展示了我的問題的簡化版本。如果DTO是許多不同對象的組成部分呢?請參閱 – 0x6B6F77616C74

+0

更新 –