这个问题是我先前的问题的后续。我需要检索复杂类的列表。
我需要找到一个特定组的学生列表,这些学生位于特定的位置,其电话号码位于其地址中。我还需要显示每个学生到特定坐标的距离。
下面的代码工作正常,唯一的问题是我无法检索对象列表,例如电子邮件列表,组列表和每个学生的电话列表。
@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();
hibernate的默认类不会传输嵌套对象,如果您遇到性能问题,应尝试以下代码。
看看这个链接和这一个是提高该版本。
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<?>>(); } }