2013-05-11 2 views
1

Я пытаюсь создать запрос, используя CriteriaBuilder, чтобы выбрать все Product с запасом, большим нуля. Фондовый - sum(DeliveryRow.amount) - sum(DispatchRow.amount). Оба они имеют только право Product.CriteriaBuilder join/subquery с результирующим Integer

Я попытался создать Subquery как для DeliveryRow и DispatchRow, хотя я чувствую, что это должно быть сделано с помощью join().

Классы

Product { 
    (...) 
} 

DeliveryRow { 
    @ManyToOne 
    private Product product; 

    private int amount; 
} 

DispatchRow { 
    @ManyToOne 
    private Product product; 

    private int amount; 
} 

Запрос

В этом запросе я не знаю, как справиться с xxx. Я пробовал делать подзапросы, но это не сработало.

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Product> query = cb.createQuery(Product.class); 
Root product = query.from(Product.class); 
query.select(product); 

// sum of DeliveryRow.amount where DeliveryRow.product = Product 
// minus 
// sum of DispatchRow.amount where DispatchRow.product = Product 
Expression stock = xxx; 

query.where(cb.gt(stock, Integer.parseInt(0))); 
return em.createQuery(query).getResultList(); 

Любые предложения по тому, как это решить?

ответ

0

Я недавно занимался исследованиями JPA/JPQL, изучая три разных подхода к извлечения объектов: NamedQueries, em.CreateQuery и CriteriaBuilder. КритерийBuilder, на мой взгляд, самый неудобный из трех, чтобы использовать. Я бы рекомендовал создать NamedQuery для обработки этой ситуации, его будет намного проще реализовать и прочитать.

Используя это выражение JPQL вы можете получить все продукты с запасом больше нуля:

SELECT p.name, SUM(delRow.amount) - SUM(disRow.amount) 
FROM Product p join p.deliveryRows delRow join p.dispatchRows disRow 
HAVING SUM(delRow.amount) - SUM(disRow.amount) > 0 

/* This assumes product has a Collection<DispatchRow> named dispatchRows 
    and a Collection<DeliveryRow> named deliveryRows. 
*/ 

сделать это именованный запрос в сущности в `продукта»

//This should be concatenated or on one line 
@NamedQuery(name="Product.hasStock" 
    query="SELECT p.name, SUM(delRow.amount) - SUM(disRow.amount) 
    FROM Product p join p.deliveryRows delRow join p.dispatchRows disRow 
    HAVING SUM(delRow.amount) - SUM(disRow.amount) > 0"); 

Затем выполнить это запрос с EntityManager

@PersistenceContext 
EntityManager em; 

public void execute(){ 
    List<Object[]> products = 
     em.createNamedQuery("Product.hasStock").getResultList(); 

    /* Projections return a List<Object[]> where position 1 in the object array 
    corresponds with the first field in the select statement, position two 
    corresponds with the second field and so on... These can also be strongly typed 
    if an object is created and the constructor is specified in JPQL statement 
    */ 
} 

Я знаю, что это ра чем использование API критериев, но, на мой взгляд, запросы JPQL значительно превосходят API критериев. По сравнению с синтаксисом JPQL, который очень похож на SQL, API оказался менее кратким и интуитивным. Если вы решите пройти этот маршрут, я создал видеоурок, который демонстрирует @NamedQueries и показывает, как сильно печатать результаты запросов, содержащих прогнозы. Вы можете найти here.

+0

Я работал с NamedQueries раньше, хотя я использую CriteriaBuilder из-за типов безопасности, разве вы не беспокоитесь об этом? – Aquillo

+0

В чем вас беспокоит безопасность типов, объект []? –

+0

Отсутствует запрос 'String'. Любые изменения в say 'DispatchRow' могут вызвать проблемы? – Aquillo