Agustinus Verdy
Agustinus Verdy

Reputation: 7295

Map hibernate projections result to java POJO model

I've been using spring and hibernate for this past few weeks and I've always been learning something new there.

Right now I've got a problem that I want to solve with Projections in Hibernate.

Suppose there is a model Person and that model has many Car. The following are how the class definitions roughly gonna look like:

public class Person implements java.io.Serializable {
    private Integer id;
    private String name;
    private List<Car> cars;
    private Integer minYear; // Transient
    private Integer maxYear; // Transient
}

public class Car implements java.io.Serializable {
    private Integer id;
    private Integer year;
}

The problem here is I want to get the minYear (maxYear) of each Person to be filled by the earliest year (latest year) of the cars they have.

Later I found a solution to use Projections but I stumbled upon org.hibernate.QueryException: could not resolve property: minYear of: model.Person and here is the code of the db operation:

Criteria criteria = sessionFactory.getCurrentSession().createCriteria("model.Person");
            criteria.add(create(personInstance));
            criteria.createAlias("minYear", "minYear");
            criteria.setProjection(Projections.min("cars.year").as("minYear"));

Is there anyway to store the aggregation value in transient method using Projections because I just want to avoid using plain SQL and HQL as much as possible.

Upvotes: 4

Views: 8132

Answers (1)

Agustinus Verdy
Agustinus Verdy

Reputation: 7295

Never mind, I've found the solution.

  1. First we need to create alias of the associated object like so

    Criteria criteria = sessionFactory.getCurrentSession().createCriteria("model.Person");
    criteria.createAlias("cars", "cars");
    
  2. Select the needed using Hibernate Projections

    ProjectionList projections = Projections.projectionList();
    projections.add(Projections.property("id").as("id"));
    projections.add(Projections.property("name").as("name"));
    projections.add(Projections.property("cars").as("cars"));
    
  3. Group the result based on the root entity (in this case using its id, Person.id), this is needed especially when used with aggregation to group the aggregation

    projections.add(Projections.groupProperty("id"));
    
  4. Use the aggregate function

    projections.add(Projections.min("cars.year").as("minYear"));
    projections.add(Projections.max("cars.year").as("maxYear"));
    
  5. Set the projection

    criteria.setProjection(projections);
    
  6. Use result transformer AliasToBeanResultTransformer to map the result fields (as specified in step 2 & 4) to the POJO

    criteria.setResultTransformer(new AliasToBeanResultTransformer(Person.class));
    
  7. Get the result

    List<Person> results = (List<Person>) criteria.list();
    

Upvotes: 6

Related Questions