how to write Hibernate Criteria to take nested objects by Projection List?

前端 未结 3 799
名媛妹妹
名媛妹妹 2020-12-30 07:32

I want to take Nested object values in Hibernate Projection List. I having Pojo \'Charge\' and \'Tariff\' class with OneToMany and ManyToOne relations.

My sample cod

3条回答
  •  不思量自难忘°
    2020-12-30 08:26

    I've experienced this kind of requirement. I tried to get nested objects as nested objects using Transformers.aliasToBean, which will not work. By default, Transformers.aliasToBean don't have the capability to select nested object as nested object.

    You can take a look at my question

    Using Projecions to fetch a particular column from child table

    To get Nested object as nested object, you need a Custom Transformer which is capable of doing that.

    Here's a Custom Transformer written by samiandoni

    https://github.com/samiandoni/AliasToBeanNestedResultTransformer

    From the provided Readme in that link

    class Person {
      private Long id;
      private String name;
      private Car car;
      // getters and setters
    }
    
    class Car {
      private Long id;
      private String color;
      // getters and setters
    }
    
    List getPeople() {
      ProjectionList projections = Projections.projectionList()
        .add(Projections.id().as("id"))
        .add(Projections.property("name").as("name"))
        .add(Projections.property("c.id").as("car.id"))
        .add(Projections.property("c.color").as("car.color"));
    
      Criteria criteria = getCurrentSession().createCriteria(Person.class)
        .createAlias("car", "c")
        .setProjection(projections)
        .setResultTransformer(new AliasToBeanNestedResultTransformer(Person.class));
    
      return (List) criteria.list();
    }
    
    // each car of Person will be populated
    

    The above transformer is capable of Fetching first level Nested object as Nested object and it doesn't support further deep nested objects. So after some digging I've found another Custom transformer which is capable of Fetching deep Nested objects as Nested objects

    Note:

    Author: Miguel Resendiz

    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import org.hibernate.HibernateException;
    import org.hibernate.property.PropertyAccessor;
    import org.hibernate.property.PropertyAccessorFactory;
    import org.hibernate.property.Setter;
    import org.hibernate.transform.AliasToBeanResultTransformer;
    import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
    import org.hibernate.transform.ResultTransformer;
    
    /**
     * Help to transform alises with nested alises
     * 
     * @author Miguel Resendiz
     * 
     */
    public class AliasToBeanNestedResultTransformer extends
    AliasedTupleSubsetResultTransformer {
    
        private static final long serialVersionUID = -8047276133980128266L;
    
        private static final int TUPE_INDEX = 0;
        private static final int ALISES_INDEX = 1;
        private static final int FIELDNAME_INDEX = 2;
    
        private static final PropertyAccessor accessor = PropertyAccessorFactory
                .getPropertyAccessor("property");
    
        private final Class resultClass;
    
        private Object[] entityTuples;
        private String[] entityAliases;
    
        private Map> fieldToClass = new HashMap>();
        private Map> subEntities = new HashMap>();
        private List nestedAliases = new ArrayList();
        private Map> listFields = new HashMap>();
    
        public boolean isTransformedValueATupleElement(String[] aliases,
                int tupleLength) {
            return false;
        }
    
        public AliasToBeanNestedResultTransformer(Class resultClass) {
    
            this.resultClass = resultClass;
        }
    
        public Object transformTuple(Object[] tuple, String[] aliases) {
    
            handleSubEntities(tuple, aliases);
            cleanParams(tuple, aliases);
            ResultTransformer rootTransformer = new AliasToBeanResultTransformer(
                    resultClass);
            Object root = rootTransformer.transformTuple(entityTuples,
                    entityAliases);
    
            loadSubEntities(root);
    
            cleanMaps();
            return root;
        }
    
        private void handleSubEntities(Object[] tuple, String[] aliases)
                throws HibernateException {
            String fieldName = "";
            String aliasName = "";
            try {
                for (int i = 0; i < aliases.length; i++) {
                    String alias = aliases[i];
                    if (alias.contains(".")) {
    
                        String[] sp = alias.split("\\.");
                        StringBuilder aliasBuilder = new StringBuilder();
                        for (int j = 0; j < sp.length; j++) {
                            if (j == 0) {
                                fieldName = sp[j];
                            } else {
                                aliasBuilder.append(sp[j]);
                                aliasBuilder.append(".");
                            }
                        }
                        aliasName = aliasBuilder.substring(0,
                                aliasBuilder.length() - 1);
    
                        nestedAliases.add(alias);
                        manageEntities(fieldName, aliasName, tuple[i]);
                    }
                }
            } catch (NoSuchFieldException e) {
                throw new HibernateException("Could not instantiate resultclass: "
                        + resultClass.getName() + " for field name: " + fieldName
                        + " and alias name:" + aliasName);
            }
        }
    
        private Class findClass(String fieldName) throws NoSuchFieldException,
        SecurityException {
            if (fieldToClass.containsKey(fieldName)) {
                return fieldToClass.get(fieldName);
            } else {
                Class subclass = resultClass.getDeclaredField(fieldName)
                        .getType();
    
                if (subclass.equals(List.class) || subclass.equals(Set.class)) {
                    if (subclass.equals(List.class)) {
                        listFields.put(fieldName, LinkedList.class);
                    } else {
                        listFields.put(fieldName, HashSet.class);
                    }
                    Field field = resultClass.getDeclaredField(fieldName);
                    ParameterizedType genericType = (ParameterizedType) field
                            .getGenericType();
                    subclass = (Class) genericType.getActualTypeArguments()[0];
    
                }
                fieldToClass.put(fieldName, subclass);
                return subclass;
            }
        }
    
        @SuppressWarnings("unchecked")
        private void manageEntities(String fieldName, String aliasName,
                Object tupleValue) throws NoSuchFieldException, SecurityException {
            Class subclass = findClass(fieldName);
            if (!subEntities.containsKey(fieldName)) {
                List list = new ArrayList();
                list.add(new ArrayList());
                list.add(new ArrayList());
                list.add(FIELDNAME_INDEX, subclass);
                subEntities.put(fieldName, list);
            }
            ((List) subEntities.get(fieldName).get(TUPE_INDEX))
            .add(tupleValue);
            ((List) subEntities.get(fieldName).get(ALISES_INDEX))
            .add(aliasName);
        }
    
        private void cleanParams(Object[] tuple, String[] aliases) {
            entityTuples = new Object[aliases.length - nestedAliases.size()];
            entityAliases = new String[aliases.length - nestedAliases.size()];
    
            for (int j = 0, i = 0; j < aliases.length; j++) {
                if (!nestedAliases.contains(aliases[j])) {
                    entityTuples[i] = tuple[j];
                    entityAliases[i] = aliases[j];
                    ++i;
                }
            }
        }
    
        @SuppressWarnings({ "unchecked", "rawtypes" })
        private void loadSubEntities(Object root) throws HibernateException {
            try {
                for (String fieldName : subEntities.keySet()) {
                    Class subclass = (Class) subEntities.get(fieldName).get(
                            FIELDNAME_INDEX);
    
                    ResultTransformer subclassTransformer = new AliasToBeanNestedResultTransformer(
                            subclass);
    
                    Object subObject = subclassTransformer.transformTuple(
                            ((List) subEntities.get(fieldName).get(0))
                            .toArray(),
                            ((List) subEntities.get(fieldName).get(1))
                            .toArray(new String[0]));
    
                    Setter setter = accessor.getSetter(resultClass, fieldName);
                    if (listFields.containsKey(fieldName)) {
                        Class collectionClass = listFields.get(fieldName);
                        Collection subObjectList = (Collection) collectionClass
                                .newInstance();
                        subObjectList.add(subObject);
                        setter.set(root, subObjectList, null);
                    } else {
                        setter.set(root, subObject, null);
                    }
                }
            } catch (Exception e) {
                throw new HibernateException(e);
            }
        }
    
        private void cleanMaps() {
            fieldToClass = new HashMap>();
            subEntities = new HashMap>();
            nestedAliases = new ArrayList();
            listFields = new HashMap>();
        }
    
    }
    
    
    

    Just replace samiandoni's Transformer with the above transformer. It's capable of fetching further deep Nested Objects as respective Objects.

    提交回复
    热议问题