簡體   English   中英

JPA ManyToMany關系和JSON序列化

[英]JPA ManyToMany relationship and JSON serialization

我正在使用Spring Framework v3.2.4和JPA + Hibernate 4實現RESTful服務。我以JSON格式返回資源(使用Jackson Mapper),但是現在我遇到了以下異常:

Could not write JSON: failed to lazily initialize a collection of role: it.teck.service.model.Canvas.params, could not initialize proxy - no Session (through reference chain: it.teck.service.model.Canvas["params"]);

我在CanvasParam實體之間存在“多對多”關系,當向服務請求畫布時,我還需要序列化params列表。

在我的課程中,我有:

@Entity
public class Canvass {

    @ManyToMany
    @JoinTable(name = "canvas_params", joinColumns = { @JoinColumn(name = "id_canvas", referencedColumnName = "id_canvas") }, inverseJoinColumns = { @JoinColumn(name = "id_param", referencedColumnName = "id_param") })
        private List<Param> params;

    // ...
}

和:

@Entity
public class Param {

    @ManyToMany(mappedBy = "params")
    private List<Canvas> canvasList;

    // ...
}

在幾篇文章中,建議使用SO答案從序列化中排除ManyToMany字段,以打破序列化循環,但是我需要對鏈接到我的canvas實體的參數進行序列化 所以我該怎么做?

由於序列化時的Hibernate延遲加載,您最終將獲得Hibernate代理集合。 目前會話已經關閉或不在范圍內。 您可以編寫一個在范圍內具有JPA實體管理器的自定義轉換器(查找OpenEntityManagerInViewFilter示例),或者如果性能不成問題(集合很小)並且您始終需要完全填充的對象,則可以指定一個急切的獲取策略在映射上為:

@ManyToMany(fetch = FetchType.EAGER) 
@JoinTable(name = "canvas_params", joinColumns = { @JoinColumn(name = "id_canvas", referencedColumnName = "id_canvas") }, inverseJoinColumns = { @JoinColumn(name = "id_param", referencedColumnName = "id_param") })
    private List<Param> params;

發生這種情況是因為Jackson嘗試在會話外部訪問由Hibernate管理的bean的屬性。 因此,該屬性是延遲加載的,當您嘗試在會話外訪問該屬性時,hibernate將無法從數據庫中獲取它。

您有三種選擇:

  1. 您確實像Ion所說的那樣,在實體上設置了FetchType.EAGER。 不利之處在於,每次以這種方式獲取一個實體時,它都會獲取與之鏈接的所有畫布和參數。 而且您可能不希望這樣做,因為這可能會降低您的應用程序運行速度。
  2. 在仍處於DAO級別或Service級別的會話中時,可以對其進行序列化。 這是最干凈,最正確的方法
  3. 最后,如果(仍然在會話中)執行諸如params.size()或canvasList.size()之類的操作,這將自動觸發從db獲取集合。 這有點駭人聽聞,但確實可行,您不必修改實體的DAO簽名或獲取策略。

對於Spring,還有另一種選擇,其中包括在進行序列化的控制器方法中進行@Transactional,這將使會話保持打開狀態! 但這會使該方法具有事務性,因此請小心不要產生不良后果。

您的問題似乎並沒有鏈接到序列化循環,而是鏈接到在檢索父對象的事務之外完成的序列化。

要解決此問題,可以在此TX內進行序列化嗎?

您還有其他幾個選項,在休眠的“延遲初始化異常”線程中有描述,例如: 無法延遲初始化角色集合

提供的其他答案確實涵蓋了問題的原因。 對於該解決方案,我建議您研究類似“六角結構”之類的東西。

本質上,您需要一個存儲庫層,在其中可以獲取要使用的數據,方法是強制您將自己從Entity數據對象映射到Domain數據對象,從而實際上可以避免此問題。 原因是您要分開關注點。 您要在一個位置加載所有將要使用的數據(而不是多余的數據),然后在不同的位置執行任何邏輯。 這將具有先完成所有數據庫工作並釋放這些資源的效果,以便您隨后可以隨意執行邏輯。

為此使用的一個很好的鏈接是: http : //alistair.cockburn.us/Hexagonal+architecture

即使您的實現不嚴格,應用它所談論的某些學科也會極大地幫助您。

希望這可以幫助。

您可以嘗試以下方法在運行時更改獲取策略,以解決此問題。

User user = (User) session.createCriteria(User.class)
    .setFetchMode("permissions", FetchMode.JOIN)
    .add( Restrictions.idEq(userId) )
    .uniqueResult();

“ FetchMode”中沒有更多選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM