如何使用Hibernate检索一组成员对象?
这个问题是跟进我之前的问题 。 我需要检索复杂类的列表。 每个都有几个集合,只应检索其中的特定数量。 我已经阅读了这些问题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 groups = new HashSet(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 phones = new HashSet(); 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 = (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> 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
这是个好问题。 我遇到过类似的问题。 因此,AliasToBeanResultTransformer仅将主对象转换为实体,但它无法选择嵌套对象作为嵌套对象。
要获取嵌套对象,我们应该使用Custom Transformer。 这是一个例子:
https://github.com/madhupathy/Hibernate-Custom-Transformer
我避免在这种情况下进行投影并获取所有对象以保持简单,如果没有巨大的性能影响,我几乎需要所有值。