2015-05-31 24 views
3

我需要查找特定組中位於特定地址的學生列表,以及他們的位置中的電話號碼。如何使用Hibernate預測進行分組

我的主要問題是我無法檢索每個學生的電話號碼作爲一個集合。例如,如果我有student1,student2。電話1111爲位置1中的學生1和電話2222和電話3333爲位置1中的學生2以及位置2中的學生2爲電話444。

比方說我有一個數據

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 

換句話說

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 

樣本輸出,我想有學生名單與它們的位置沿和所選位置的電話。

對我當前的代碼

org.springframework.orm.hibernate4.HibernateSystemException: 
IllegalArgumentException occurred while calling setter for property 
[com.example.Address.phones (expected type = java.util.List)]; target 
= [[email protected]], 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 = [[email protected]], 
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<?>>(); 
    } 

} 

回答

1

AliasToBeanNestedResultTransformer支持嵌套的DTO但它不不支持的DTO的類別。

您可以更改AllStudent DTS到:

public class AllStudents { 
    Student student; 
    String phone; 
    Location location; 

    public AllStudents(Student student, String phone, Location location) { 
     this.student = student; 
     this.phone = phone; 
     this.location = location; 
    } 

    public Student getStudent() { 
     return student; 
    } 

    public String getPhone() { 
     return phone; 
    } 

    public Location getLocation() { 
     return location; 
    } 
} 

,你需要添加一個StudentDTO舉行聚合的結果:

public class StudentDTO { 
    private final Student student; 
    private String location; 
    private List<String> phones = new ArrayList<>(); 

    public StudentDTO(Student student) { 
     this.student = student; 
    } 

    public Student getStudent() { 
     return student; 
    } 

    public String getLocation() { 
     return location; 
    } 

    public void setLocation(String location) { 
     this.location = location; 
    } 

    public List<String> getPhones() { 
     return phones; 
    } 
} 

現在,當你運行你查詢你的列表全部學生:

List<AllStudents> allStudents = ... 

你簡單的這樣分組:

LinkedHashMap<Long, StudentDTO> studentMap = new LinkedHashMap<>(); 

for(AllStudents all : allStudents) { 
    StudentDTO studentDTO = studentMap.get(all.getStudent().getId()); 
    if(studentDTO == null) { 
     studentDTO = new StudentDTO(all.getStudent()); 
     studentMap.put(all.getStudent().getId(), studentDTO); 
    } 
    if(all.getPhone() != null) { 
     studentDTO.getPhones().add(all.getPhone()); 
    } 
    studentDTO.setLocation(all.getLocation()); 
} 

List<StudentDTO> studentDTOs = new ArrayList<>(studentMap.values()); 
+0

謝謝,我想你讓我錯了。我不想讓他們的手機有學生的地圖。我只想收集學生對象和他/她各自對象中每個人的電話列表。問題已更新。真的很抱歉給我帶來不便 – Jack

+1

我明白了。檢查我更新的答案。 –

相關問題