Complex Hibernate Projections

前端 未结 4 730
野的像风
野的像风 2020-12-18 08:06

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 = \"p         


        
相关标签:
4条回答
  • 2020-12-18 08:27

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

    0 讨论(0)
  • 2020-12-18 08:29

    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();
    
    0 讨论(0)
  • 2020-12-18 08:31

    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;
    ...
    }
    
    0 讨论(0)
  • 2020-12-18 08:31

    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();
    
    0 讨论(0)
提交回复
热议问题