2014-02-17 1 views
2

Я пытаюсь получить сумму с одного до многих отношениях, иллюстрируется следующим соотношением (только родитель показано):Сумма с одного до многих Spring Data JPA

@Entity 
@Table(name = "Parent") 
public class Parent implements Serializable { 
    private static final long serialVersionUID = -7348332185233715983L; 

    @Id 
    @Basic(optional = false) 
    @Column(name = "PARENT_ID") 
    private Long parentId; 

    @OneToMany 
    @JoinColumn(name="CHILDREN", referencedColumnName="PARENT_ID") 
    private List<Child> children; 

    @Formula("(select sum(select height from children))") 
    private BicDecimal totalHeight 
} 

Это не довольно прямо вперед нет ограничения и даже со статическими ограничениями. У меня возникают проблемы, когда список детей ограничен динамически.

В моем случае я использую данные весны и jpa. Я использую спецификации для ограничения детей и получаю соответствующий список детей, но, очевидно, сумма по-прежнему остается для неограниченных детей, потому что в теге @Formula нет предложения where.

Я не хочу перебирать список в java по соображениям производительности и потому, что результаты разбиты на страницы. Кроме того, сумма не состоит из разбитых на страницы результатов, но и всех результатов.

Я новичок в Spring Data/JPA. Исторически я мог бы построить этот запрос динамически или использовать критерии спящего режима. Я выполняю полный запрос на завершение, чтобы сделать этот расчет. не требуется, чтобы я использовал аннотацию @Formula, поскольку для каждого звонка есть только 1 агрегирование. В рамках hibernate я могу просто указать предложение select как «sum (field)» и построить критерии. В рамках Spring Data/JPA я могу создать спецификации, которые покрывают критерии, но я не знаю, как манипулировать выбранной частью запроса, поскольку он кажется настолько тесно привязанным к объекту.

Использование аннотации @Query в репозитории работает как собственный запрос, если я знаю, какие поля мне нужно ограничить, но часто поля имеют нулевое значение и их нужно игнорировать. Есть 8 возможных полей, оставляя мне 256 возможных комбинаций (2^8). Это слишком много методов для этого в репозитории.

Любые идеи за пределами коммутационных систем?

ответ

0

Вы пробовали в JPQL

select sum(d.height) from Parent a join a.children d 

Если вы не хотите, чтобы игнорировать аннулирует

select sum(d.height) from Parent a left join a.children d 

Я думаю, другой вопрос, у вас есть как фильтр в зависимости от свойств. Я имею в виду, если вам нужно иметь оператор where с несколькими комбинациями.

Почему вы не пытаетесь использовать список и добавляете в список все предикаты, которые хотите применить, в зависимости от комбинаций, которые вы хотите использовать. Пример

Создать запрос

CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery cq = cb.createQuery(Double.class); 
    Root<Parent> root = cq.from(Parent.class) 
    Join<Parent, Child> join = cq.join(("children")); 
    cq.select(cb.<Double>sum(join.get("height"))); 

Создать список предикатами

List<Predicates> listOfpredicates = new ArrayList<Predicates>(); 
if(property1 != null && !"".equals(property1){ 
     PatameterExpression<String> p = cb.parameter(String.class, "valueOfproperty1") 
     listOfpredicates.add(cb.equal(join.get("property1"),p); 
} 

Затем добавить к CriteriaQuery

if(listOfPredicates.size() == 1) 
    cq.where(listOfPredicates.get(0)) 
else 
    cq.where(cb.and(listOfPredicates.toArray(new Predicate[0]))); 

Наконец выполнить запрос.

TypedQuery<Double> q = em.createQuery(cq); 
q.getResultList(); 

Это будет динамически создавать ваши запросы с любой комбинацией.

0

Опубликовать ответ на этот старый вопрос, так как в последнее время у меня была аналогичная проблема.

Я решил пойти с настраиваемым репозиторием с помощью метода, который выполняет агрегацию на основе любой Спецификации, переданной в нее. Технические характеристики могут быть объединены, чтобы составить динамические критерии (см org.springframework.data.jpa.domain.Specifications)

Так что мой репозитарий выше проблемы высоты Ребенок будет выглядеть следующим образом:

package something 

import org.springframework.data.jpa.domain.Specification; 
import org.springframework.stereotype.Repository; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.persistence.criteria.CriteriaBuilder; 
import javax.persistence.criteria.CriteriaQuery; 
import javax.persistence.criteria.Root; 

@Repository 
public class ChildHeightRepository { 

    @PersistenceContext 
    EntityManager entityManager; 


    public Long getTotalHeight(Specification<Child> spec) { 

     CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 

     CriteriaQuery query = cb.createQuery(Long.class); 

     Root root = query.from(Child.class); 

     return ((Long) entityManager.createQuery(
       query.where(spec.toPredicate(root, query, cb)) 
         .select(cb.sum(root.get("height")))).getSingleResult()); 


    } 
}