5

I want to ask, it is possible that I create query projections and criterion for more than one level deep? I have 2 model classes:

@Entity @Table(name = "person") public class Person implements Serializable { @Id @GeneratedValue private int personID; private double valueDouble; private int valueInt; private String name; @OneToOne(cascade = {CascadeType.ALL}, orphanRemoval = true) @JoinColumn(name="wifeId") private Wife wife; /* * Setter Getter */ } @Entity @Table(name = "wife") public class Wife implements Serializable { @Id @GeneratedValue @Column(name="wifeId") private int id; @Column(name="name") private String name; @Column(name="age") private int age; /* * Setter Getter */ } 

My Criteria API :

ProjectionList projections = Projections.projectionList(); projections.add(Projections.property("this.personID"), "personID"); projections.add(Projections.property("this.wife"), "wife"); projections.add(Projections.property("this.wife.name"), "wife.name"); Criteria criteria = null; criteria = getHandlerSession().createCriteria(Person.class); criteria.createCriteria("wife", "wife", JoinType.LEFT.ordinal()); criterion = Restrictions.eq("wife.age", 19); criteria.add(criterion); criteria.setProjection(projections); criteria.setResultTransformer(Transformers.aliasToBean(Person.class)); return criteria.list(); 

and I hope, I can query Person, with specified criteria for wife property, and specified return resultSet. so i used Projections for getting specified return resultSet

I want personID, name(Person), name(Wife) will returned. how API i must Use, i more prefer use Hibernate Criteria API.

This time, I used code above for getting my expected result, but it will throw Exception with error message : Exception in thread "main" org.hibernate.QueryException: could not resolve property: wife.name of: maladzan.model.Person, and whether my Restrictions.eq("wife.age", 19); is correct for getting person which has wife with 19 as her age value ?

Thanks

0

4 Answers 4

6

AFAIK it is not possible to project more than one level deep with aliastobean transformer. Your options are

  • create a flattened Data Transfer Object (DTO)
  • fill the resulting Person in memory yourself
  • implement your own resulttransformer (similar to option 2)

option 1 looks like this:

Criteria criteria = getHandlerSession().createCriteria(Person.class) .createAlias("wife", "wife", JoinType.LEFT.ordinal()) .add(Restrictions.eq("wife.age", 19)); .setProjection(Projections.projectionList() .add(Projections.property("personID"), "personID") .add(Projections.property("name"), "personName") .add(Projections.property("wife.name"), "wifeName")); .setResultTransformer(Transformers.aliasToBean(PersonWifeDto.class)); return criteria.list(); 
Sign up to request clarification or add additional context in comments.

Comments

5

I wrote the ResultTransformer, that does this exactly. It's name is AliasToBeanNestedResultTransformer, check it out on github.

4 Comments

Hi Sami Andoni. I did used your AliasToBeanNestedResultTransformer for nested object creation, I do get nested object as nested object, but I've a small Issue. I intend to get only particular field in nested object, only few fields in parent object, but the outcome is all fields in parent object and all fields in nested object as nested object. I dont know whether your custom transformer is capable for fetching only a particular field, is it possible to fetch only a particular field in nested object as nested object?
Have u solvd this issue?
@JatinMalwal what issue?
I'm trying to do the same thing to fetch only particular fields using AliasToBeanNestedResultTransformer. But AliasedTupleSubsetResultTransformer is not found when I'm try to make this.
1

Thanks Sami Andoni. I was able to use your AliasToBeanNestedResultTransformer with a minor modification to suit my situation. What I found was that the nested transformer did not support the scenario where the field is in a super class so I enhanced it to look for fields up to 10 levels deep in the class inheritance hierarchy of the class you're projecting into:

 public Object transformTuple(Object[] tuple, String[] aliases) { ... if (alias.contains(".")) { nestedAliases.add(alias); String[] sp = alias.split("\\."); String fieldName = sp[0]; String aliasName = sp[1]; Class<?> subclass = getDeclaredFieldForClassOrSuperClasses(resultClass, fieldName, 1); ... } 

Where getDeclaredFieldForClassOrSuperClasses() is defined as follows:

private Class<?> getDeclaredFieldForClassOrSuperClasses(Class<?> resultClass, String fieldName, int level) throws NoSuchFieldException{ Class<?> result = null; try { result = resultClass.getDeclaredField(fieldName).getType(); } catch (NoSuchFieldException e) { if (level <= 10){ return getDeclaredFieldForClassOrSuperClasses( resultClass.getSuperclass(), fieldName, level++); } else { throw e; } } return result; } 

My Hibernate projection for this nested property looked like this:

Projections.projectionList().add( Property.forName("metadata.copyright").as("productMetadata.copyright")); 

and the class I am projecting into looks like this:

public class ProductMetadata extends AbstractMetadata { ... } public abstract class AbstractMetadata { ... protected String copyright; ... } 

2 Comments

Did you write a NestedTransformer which can support OneToMany (Collections) ?
@Sangdol wrote it, I just enhanced it to support projecting into fields from a base class up to 10 levels deep
-1

Instead of creating Data Transfer Object (DTO)
In projectionlist make below changes and it will work for you.

 ProjectionList projections = Projections.projectionList(); projections.add(Projections.property("person.personID"), "personID"); projections.add(Projections.property("person.wife"), "wife"); projections.add(Projections.property("wife.name")); Criteria criteria = null; criteria = getHandlerSession().createCriteria(Person.class,"person").createAlias("person.wife", "wife"); criterion = Restrictions.eq("wife.age", 19); criteria.add(criterion); criteria.setProjection(projections); criteria.setResultTransformer(Transformers.aliasToBean(Person.class)); return criteria.list(); 

1 Comment

not working is different word, provide your hibernate version and full query

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.