2010-09-04 61 views
4

有兩個JPA實體:用戶和具有一對多關係的順序。使用延遲初始化屬性分離JPA對象

/** 
* User DTO 
*/ 
@Entity 
@Table(name="user") 
public class User implements Serializable { 
    private static final long serialVersionUID = 8372128484215085291L; 

    private Long id; 
    private Set<Order> orders; 

    public User() {} 

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceUser") 
    public Long getId() { 
     return this.id; 
    } 
    private void setId(Long id) { 
     this.id = id; 
    } 

    @OneToMany(mappedBy="user", cascade=CascadeType.PERSIST, fetch=FetchType.LAZY) 
    @LazyCollection(LazyCollectionOption.EXTRA) 
    public Set<Order> getOrders() { 
     return orders; 
    } 
    public void setOrders(Set<Order> orders) { 
     this.orders = orders; 
    } 
} 


/** 
* Order DTO 
*/ 
@Entity 
@Table(name="order") 
public class Order implements Serializable { 
    private static final long serialVersionUID = 84504362507297200L; 

    private Long id; 
    private User user; 

    public Order() { 
    } 

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceOrder") 
    public Long getId() { 
     return this.id; 
    } 
    private void setId(Long id) { 
     this.id = id; 
    } 

    @ManyToOne 
    @JoinColumn(name="user_id") 
    public User getUser(){ 
     return user; 
    } 
    public void setUser(User user){ 
     this.user = user; 
    } 
} 

我在我的服務層類中使用這些實體,其中每個方法都在事務中運行。除了服務層類的方法必須返回這些實體的情況之外,一切都很好。

@Transactional(readOnly=true) 
public Set<Order> getOrders() { 
    Set<Order> orders = user.getOrders(); 

    return orders; 
} 

該方法很好地返回數據。但是,當我嘗試訪問收到的集合元素時,我發現異常:「org.hibernate.LazyInitializationException:未能懶惰地初始化一個角色集合:package.User.orders,沒有會話或會話被關閉」。

因此,它是例外。我認爲,分離結果將解決我的問題,而是欺騙這樣

@Transactional(readOnly=true) 
public Set<Order> getOrders() { 
    Set<Order> orders = user.getOrders(); 

    for(Order order: orders) 
     entityManager.detach(order); 
    return orders; 
} 

沒有改變任何東西:(

它不適合我沒關係將有關用戶信息的集合訂單或不參加我只是想用這組的工作,而不是去修改它。

任何人可以幫助我嗎?:)因爲數據請求交易之外發生

回答

6

該方法可以很好地返回數據。但是,當我嘗試訪問收到的集合元素時,我發現異常:「org.hibernate.LazyInitializationException:未能懶惰地初始化一個角色集合:package.User.orders,沒有會話或會話被關閉」。

錯誤是自我解釋:您試圖加載(懶惰)加載的集合,但由於User實例已分離,因此不再有活動會話。

因此,它是例外。我認爲分離結果將解決我的問題,但這樣的技巧

這不會改變任何東西。 EntityManager#detach(Object)方法不會加載什麼,它將從持久化上下文中刪除傳遞的實體,使其脫離分離

這對我來說無關緊要,關於用戶出席一組訂單或不。我只想使用這個集合,而不會去修改它。

您需要可以使聯想迫切,使用FETCH檢索在服務用戶時JOIN(使訂單將檢索用戶時加載):

SELECT u 
FROM User u LEFT JOIN FETCH u.orders 
WHERE u.id = :id 

我是否理解正確的話Hibernate沒有標準的機制,力負載電流對象的所有延遲關聯

Hibernate有一個Hibernate.initialize方法,但這顯然不是標準的JPA(更喜歡用於便攜式代碼的fetch連接)。

我有沒有辦法讓休眠忽略當前的對象(它們設置爲NULL)

什麼的延遲關聯?你忽略了什麼意思?你爲什麼要這樣做?

+0

謝謝。我想澄清兩點:我是否正確理解hibernate沒有強制加載當前對象的所有惰性關聯的標準機制 - 只有適當的方法或查詢調用?我沒有辦法讓休眠忽略當前對象的惰性關聯(將它們設置爲空)? – mikhail 2010-09-06 01:22:15

+0

我明白,試圖忽視懶惰的嘗試是錯誤的,但我純粹有學術興趣。例如,我通過實體管理器獲得了User類的對象:「User user = entityManager(User.class,1)」。此時「訂單」屬性等於空,因爲它很懶。是否有可能從休眠狀態「分離」對象「用戶」,以防止訪問方法「getOrders」期間的屬性「命令」初始化? – mikhail 2010-09-06 11:09:32

+0

@mikhail'在Hibernate論壇的訪問方法「getOrders」中搜索「unproxy」或「deproxy」,是否可以從hibernate中「分離」對象「用戶」 – 2010-09-07 07:08:50

0

的LazyInitialisationException。如果你需要這些數據,你必須在一個事務中請求它 - 在你的情況下,這將在服務方法中。

您可以通過多種方式請求數據加載。最簡單的:

for(Order order: orders) 
    order.getX() 

(其中X是比Id或其他版本的某些屬性)

然而,這將加載在一個單獨的查詢,如果有很多訂單是慢的每個訂單。更快的方法是發出返回該用戶所有訂單的查詢(JP-QL或Criteria)。 (編輯:查看Pascal的回答以獲得合適的查詢。)