Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Projections in JPA 2

I need to convert a Hibernate criteria query like the following

curList = session.createCriteria(Islem.class)
                    .createAlias("workingDay", "d")
                    .setProjection(Projections.sum("amount"))
                    .add(Restrictions.eq("currency", CURRENCY))
                    .add(Restrictions.eq("product", product))
                    .add(Restrictions.ne("status", INACTIVE))
                    .add(Restrictions.eq("d.status", ACTIVE))
                    .getResultList();

However in JPA (2) I have no idea how to implement the projection - in this case - the sum. It's odd that Hibernate and JPA (even Hibernate JPA 2) have this tremendous differences especially in criteria queries.

I start by

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Islem> cq = cb.createQuery(Islem.class);
Root<Islem> isr = cq.from(Islem.class);
cq.select(isr).where(cb.equal(isr.get("currency"), CURRENCY), 
                     cb.notEqual(isr.get("status"), INACTIVE),
                     cb.equal(isr.get("product"), product));

however have no idea how to implement the projection here neither the alias

like image 642
Skyhan Avatar asked Mar 21 '12 10:03

Skyhan


People also ask

What is projection in JPA?

Projection is one of the first things you're probably thinking about when implementing a query with Spring Data JPA. This is because projection defines the entity attributes and the database columns returned by your query. So, selecting the right columns is important for your business logic.

What are DTO projections?

A DTO projection is a Java Object that contains the column values that were fetched by a given SQL projection query. The DTO projection can be a POJO (Plain Old Java Object), a JPA Tuple , or a Java Record, and we can fetch all those DTO projection types using Spring Data JPA.

How projection is used in Hibernate?

To put it simple, Hibernate Projections are used in order to query only a subset of the attributes of an entity or group of entities you're querying with Criteria. You can also use Projections to specify distinct clauses and aggregate functions like max , sum and so on.

How do you fetch a one to many DTO projection with JPA and Hibernate?

Fetching a one-to-many DTO projection with JPA and Hibernate. The postDTOMap is where we are going to store all PostDTO entities that, in the end, will be returned by the query execution. The reason we are using the postDTOMap is that the parent rows are duplicated in the SQL query result set for each child record.


1 Answers

It's an old question, but let's give an example:

With CriteriaBuilder, unlike Hibernate, you always start off with the type of the result you want to query and then construct the projection.

CriteriaBuilder cb = em.getCriteriaBuilder();
//We want Integer result
CriteriaQuery<Integer> cq = cb.createQuery(Integer.class);

//The root does not need to match the type of the result of the query!
Root<Islem> isr = cq.from(Islem.class);

//Create a join to access the variable status of working day
Join<Islem,WorkingDay> join = isr.join("workingDay",JoinType.INNER);

//Create the sum expression
Expression<Integer> sum = cb.sum(isr.get("amount"));

cq.where(
         cb.equal(isr.get("currency"), CURRENCY),
         cb.notEqual(isr.get("status"), INACTIVE),
         cb.equal(isr.get("product"), product),
         cb.equal(join.get("status"), ACTIVE)
).select(sum);

On the other hand if you wanted to query for the actual "amount" values, you could do:

CompoundSelection<Integer> projection = cb.construct(Integer.class, cb.sum(isr.get("amount")));

cq.where(..).select(projection);

List<Integer> amounts = em.createQuery(cq).getResultList();
like image 99
user2037910 Avatar answered Sep 28 '22 08:09

user2037910