我需要找到一个特定组内和特定地址中的学生名单以及他们所在位置的电话号码。
我的主要问题是我无法作为集合检索出每个学生的电话号码。例如,如果我有学生1,学生2。学生1在位置1拥有电话1111,而学生2在位置1拥有电话2222和3333,在位置2拥有电话444。
假设我有
Student1 Alex group1 1111 Location1 Street1
Student3 Jack group1 93939 Location2 Street4
Student7 Joe group2 22223 Location4 Street8
Student2 John group1 2222 3333 Location1 Street1
Student2 John group1 4444 Location1 Street2
Student12 Mark group1 4423 Location9 Street9
带数据的示例输出
User asks for all students in group1 and location1
Student1 Alex Street1 phone 1111 distance30
Student2 John Street1 phones 22222,3333 distance30
Student2 John Street2 phone 4444 distance40
换句话说,我希望有一个学生列表,包括所选位置的地址和电话号码。
Hibernate返回以下错误信息,指向我的当前代码。
org.springframework.orm.hibernate4.HibernateSystemException:
IllegalArgumentException occurred while calling setter for property
[com.example.Address.phones (expected type = java.util.List)]; target
= [com.example.results.AllStudents@6deeac0], property value =
[11111111] setter of com.example.results.AllStudents.phones; nested
exception is IllegalArgumentException occurred while calling setter
for property [com.example.results.AllStudents.phones (expected type =
java.util.List)]; target = [com.example.results.AllStudents@6deeac0],
property value = [11111111]
学生
@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<AllStudents> students = (List<AllStudents) 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 AliasToBeanNestedResultTransformer(AllStudents.class))
.list();
结果类
public class AllStudents {
List<String> phones;
...
}
AliasToBeanNestedResultTransformer
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<?>>();
}
}