2012-07-12 23 views
14

tôi đang viết một hàm trong hibernate để đệ quy khởi tạo tất cả các thuộc tính của đối tượng đệ quy để toàn bộ đồ thị đối tượng được nạp.Hibernate recursive initialization

tôi có hai tình huống phức tạp nơi mà tôi cần phải sử dụng đối tượng này composit

1) tự như danh mục, chủng loại phụ ...

@Entity 
public class Category { 

    @Column(nullable = false, length = 50) 
    @NotNull 
    @Size(max = 50, message = "{50}") 
    protected String name; 

    @ManyToOne(targetEntity = Category.class, fetch = FetchType.LAZY, optional = true) 
    private Category parentCategory; 
    } 

2) phức tạp đồ thị đối tượng trong đó có rất nhiều đối tượng khởi tạo trước khi nó có thể được sử dụng.

vấn đề là tôi không thể sử dụng tìm nạp háo hức vì tôi cần đồ thị toàn bộ đối tượng này chỉ trong trường hợp chọn lọc và tôi muốn có mã tổng quát nên không cần phải viết truy vấn HQL cho đối tượng.

tôi đã viết một phần một số mã cho điều này,

public void recursiveInitliaze(Object obj) throws Exception { 
    if(!Hibernate.isInitialized(obj)) 
     Hibernate.initialize(obj); 
    PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
    for (PropertyDescriptor propertyDescriptor : properties) { 
     Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
     if (origProp != null) { 
      this.recursiveInitliaze(origProp); 
     } 
     if (origProp instanceof Collection && origProp != null) {    
      for (Object item : (Collection) origProp) { 
       this.recursiveInitliaze(item); 
      } 
     } 
    } 
} 

nhưng nó có một vấn đề, nó kết thúc vào stackoverflow cho phương pháp gọi vì các mối quan hệ hai chiều. vậy làm thế nào để phát hiện có mối quan hệ hai chiều hoặc là có cách nào tốt hơn để thực hiện điều này?

tôi nghĩ hồ sơ tìm nạp cũng có thể giúp nhưng vẫn muốn thử triển khai điều này nếu có thể vì định cấu hình hồ sơ tìm nạp ở giai đoạn hiện tại của dự án là khó khăn.

Trả lời

7

bạn có thể sử dụng Hibernate.initialize() trên đối tượng để khởi chạy. Tôi không chắc chắn nếu thác này. Nếu không, bạn có thể kiểm tra instanceof HibernateProxy cung cấp cho bạn thuộc tính isInitialised.

Cập nhật: vì khởi tạo không xếp tầng, bạn cần duyệt qua cây như bạn đã làm. Sử dụng một Hashset để theo dõi các đối tượng bạn đã xử lý.

+0

isInitialised i đã được sử dụng trong logic, nhưng vấn đề tôi đang phải đối mặt là có mối quan hệ hai chiều ví dụ Nếu Class A được kết hợp với B và cả hai chứa mỗi tham chiếu khác thì tôi sẽ luôn nhận được điều đó như là thuộc tính và nó kết thúc thành lời gọi đệ quy vô hạn. –

+0

isInitialised cung cấp cho bạn sự thật sau khi bạn khởi tạo nó một lần và bạn sẽ không cần phải xếp tầng sau đó, không có vòng lặp vô hạn. Bạn đã kiểm tra nếu khởi tạo() làm những gì bạn muốn? – Firo

+0

yes initialize() chỉ khởi tạo đối tượng hiện tại và không xếp tầng. và tôi không thể phụ thuộc vào isInitialised bởi vì nếu tôi có hệ thống phân cấp đối tượng như A chứa B, B chứa C thì ngay cả B khởi tạo C có thể không phải như vậy phải goto đối tượng B tìm C và khởi tạo. Vấn đề với mã của tôi là nếu C chứa trở lại tham chiếu đến B thì nó cố gắng gọi hàm lại. –

5

Toàn mã:

public <T> T recursiveInitliaze(T obj) { 
    Set<Object> dejaVu = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()); 
    try { 
     recursiveInitliaze(obj, dejaVu); 
    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { 
     ReflectionUtils.handleReflectionException(e); 
    } 
    return obj; 
} 

private void recursiveInitliaze(Object obj, Set<Object> dejaVu) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { 
    if (dejaVu.contains(this)) { 
     return; 
    } else { 
     dejaVu.add(this); 

     if (!Hibernate.isInitialized(obj)) { 
      Hibernate.initialize(obj); 
     } 
     PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
     for (PropertyDescriptor propertyDescriptor : properties) { 
      Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
      if (origProp != null) { 
       this.recursiveInitliaze(origProp, dejaVu); 
      } 
      if (origProp instanceof Collection && origProp != null) { 
       for (Object item : (Collection<?>) origProp) { 
        this.recursiveInitliaze(item, dejaVu); 
       } 
      } 
     } 
    } 
} 

Mã của ReflectionUtils:

/** 
* Handle the given reflection exception. Should only be called if no 
* checked exception is expected to be thrown by the target method. 
* <p>Throws the underlying RuntimeException or Error in case of an 
* InvocationTargetException with such a root cause. Throws an 
* IllegalStateException with an appropriate message else. 
* @param ex the reflection exception to handle 
*/ 
public static void handleReflectionException(Exception ex) { 
    if (ex instanceof NoSuchMethodException) { 
     throw new IllegalStateException("Method not found: " + ex.getMessage()); 
    } 
    if (ex instanceof IllegalAccessException) { 
     throw new IllegalStateException("Could not access method: " + ex.getMessage()); 
    } 
    if (ex instanceof InvocationTargetException) { 
     handleInvocationTargetException((InvocationTargetException) ex); 
    } 
    if (ex instanceof RuntimeException) { 
     throw (RuntimeException) ex; 
    } 
    throw new UndeclaredThrowableException(ex); 
}