【问题标题】:How to retrieve a set of member objects using Hibernate?如何使用 Hibernate 检索一组成员对象?
【发布时间】:2015-07-10 21:42:35
【问题描述】:

这个问题是跟进我的previous question。我需要检索复杂类的列表。每个都有几组,应该只检索其中的特定数量。我已经阅读了这些问题的答案1,2,但没有一个能解决我的问题。

我需要查找特定组中且位于特定位置的学生列表,以及他们地址中的电话号码。我还需要显示每个学生到特定坐标的距离。

以下代码工作正常,唯一的问题是我无法检索对象列表,例如每个学生的电子邮件列表、组列表和电话列表。

@Entity
public class Student implements java.io.Serializable {

    private static final long serialVersionUID = -23949494858373847L;
    @Id
    @GeneratedValue
    String id;
    String name;
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "student_groups", joinColumns = { @JoinColumn(name = "id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "groupId", nullable = false, updatable = false) })
    Set<Group> groups = new HashSet<Group>(0);
    ..
}


@Entity
public class Address implements java.io.Serializable {

    private static final long serialVersionUID = -274634747474623637L;
    @Id
    @GeneratedValue
    String addId;
    @Id
    @ManyToOne
    @JoinColumn(name = "id", nullable = false)
    Student student;
    @ManyToOne
    @JoinColumn(name = "locId", nullable = false)
    Location location;
    double latitude;
    double longitude;
    String address;
    @OneToMany(mappedBy = "phoneOwner", fetch = FetchType.EAGER)
    Set<Phone> phones = new HashSet<Phone>();


        String formula = "( 6371 * acos ( cos ( radians("
                + lat
                + ") ) * cos( radians( this_.latitude ) ) * cos( radians( this_.longitude ) - radians("
                + lan + ") ) +" + "sin ( radians(" + lat
                + ") ) * sin( radians( this_.latitude ) ) ) ) as distance";
        Session session = sessionFactory.getCurrentSession();
        ProjectionList pl = Projections
                .projectionList()
                .add(Projections.property("std.id").as("id"))
                .add(Projections.property("std.name").as("name"))
                .add(Projections.property("addr.address").as(
                        "address"))
                .add(Projections.property("location.name").as("location"))
                .add(Projections.property("location.city").as("city"))
                .add(Projections.property("location.latitude").as("latitude"))
                .add(Projections.property("location.longitude").as("longitude"))
                .add(Projections.sqlProjection(formula,
                        new String[] { "distance" },
                        new Type[] { new DoubleType() }));

        List<Students> students = (List<Students) session
                .createCriteria(Address.class, "addr")
                .createAlias("addr.student", "std")
                .createAlias("std.groups", "group")
                .createAlias("addr.location", "location")
                .setProjection(pl)
                .setFetchMode("group", FetchMode.JOIN)
                .add(Restrictions.ilike("group.name", groupName))
                .add(Restrictions.eq("location.id", locId))
                .setResultTransformer(
                        new AliasToBeanResultTransformer(Students.class))
                .list();

【问题讨论】:

    标签: java hibernate hibernate-criteria


    【解决方案1】:

    这是个好问题。我遇到过类似的问题。所以 AliasToBeanResultTransformer 只是将主对象转换为实体,但它没有选择嵌套对象作为嵌套对象的能力。

    要获得嵌套对象,我们应该使用自定义转换器。这是一个例子:

    https://github.com/madhupathy/Hibernate-Custom-Transformer

    在这种情况下,我会避免投影并获取所有对象以保持简单,如果没有巨大的性能影响并且我需要几乎所有值。

    【讨论】:

    【解决方案2】:

    hibernate 的默认类不传输嵌套对象,如果您遇到性能问题,您应该尝试以下代码。

    看看这个linkthis one,这是它的改进版本。

    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<String, Class<?>> fieldToClass = new HashMap<String, Class<?>>();
        private Map<String, List<?>> subEntities = new HashMap<String, List<?>>();
        private List<String> nestedAliases = new ArrayList<String>();
        private Map<String, Class<?>> listFields = new HashMap<String, Class<?>>();
    
        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<Object> list = new ArrayList<Object>();
                list.add(new ArrayList<Object>());
                list.add(new ArrayList<String>());
                list.add(FIELDNAME_INDEX, subclass);
                subEntities.put(fieldName, list);
            }
            ((List<Object>) subEntities.get(fieldName).get(TUPE_INDEX))
            .add(tupleValue);
            ((List<String>) 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<Object>) subEntities.get(fieldName).get(0))
                            .toArray(),
                            ((List<Object>) 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<String, Class<?>>();
            subEntities = new HashMap<String, List<?>>();
            nestedAliases = new ArrayList<String>();
            listFields = new HashMap<String, Class<?>>();
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 2013-11-28
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多