2015-05-01 39 views
17

Câu hỏi này là để theo dõi với previous question của tôi. Tôi cần lấy danh sách các lớp phức tạp. Mỗi có một vài bộ trong đó và chỉ cần một số lượng cụ thể của chúng trong số đó. Tôi đã đọc câu trả lời của những câu hỏi này 1, 2 nhưng không ai trong số họ giải quyết được vấn đề của tôi.Làm thế nào để lấy một tập hợp các đối tượng thành viên bằng Hibernate?

Tôi cần tìm danh sách sinh viên thuộc một nhóm cụ thể và ở một địa điểm cụ thể và số điện thoại của họ trong địa chỉ của họ. Tôi cũng cần hiển thị khoảng cách của từng học sinh với một tọa độ cụ thể.

Mã sau hoạt động tốt, vấn đề duy nhất là tôi không thể truy xuất danh sách đối tượng ví dụ danh sách email, danh sách nhóm và danh sách điện thoại của từng học sinh.

@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(); 

Trả lời

1

Lớp mặc định của hibernate không chuyển các đối tượng lồng nhau, nếu bạn có vấn đề về hiệu suất, bạn nên thử mã sau đây.

Hãy xem linkthis one đó là phiên bản cải tiến của điều đó.

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<?>>(); 
    } 

} 
+1

Cám ơn câu trả lời của bạn, vui lòng xem câu hỏi này cũng như http://stackoverflow.com/questions/30554572/illegalargumentexception-occurred-while-calling-setter-for-property-expected-ty – Jack

10

Đó là một câu hỏi hay. Tôi đã phải đối mặt với vấn đề tương tự. Vì vậy, AliasToBeanResultTransformer chỉ chuyển đổi đối tượng chính thành thực thể nhưng nó không có khả năng chọn đối tượng lồng nhau làm đối tượng lồng nhau.

Để nhận đối tượng lồng nhau, chúng ta nên sử dụng Custom Transformer. Dưới đây là một ví dụ:

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

tôi tránh dự báo trong trường hợp này và lấy tất cả các đối tượng để giữ cho nó đơn giản, nếu không có tác động hiệu quả rất lớn và tôi cần hầu hết tất cả các giá trị.

+0

hãy có một cái nhìn tại câu hỏi này cũng http://stackoverflow.com/questions/30554572/illegalargumentexception-occurred-while-calling-setter-for-property-expected-ty – Jack

Các vấn đề liên quan