簡體   English   中英

在 Hibernate 中延遲初始化集合

[英]Lazily initialize a collection in Hibernate

在我的托管 bean 中,我有如下代碼:

FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> map = context.getExternalContext().getRequestParameterMap();
int pageIndex = Integer.valueOf(map.get("page"));
int pageItem = Integer.valueOf(map.get("pageItem"));
int widget = Integer.valueOf(map.get("widget"));

DashboardPageItem dashboardPageItem = new DashboardPageItem();

dashboardPageItem.setPosition(pageItem);
dashboardPageItem.setWidget(widgetService.trouver(widget));

for (DashboardPage dp : dashboard.getPages()) {
    if (dp.getIndex() == pageIndex) {
        dashboardPageItem.setDashboardPage(dp);
        dp.getDashboardPageItems().add(dashboardPageItem);
    }
}

但是當我運行它時,我收到此錯誤消息:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.dashboard.entity.DashboardPage.dashboardPageItems, no session or session was closed

所以,我有一個名為Dashboard的類,這個類有一個DashboardPage列表,每個DashboardPage都有一個DashboardPageItem列表。

(請注意,當我獲取 DashboardPage 條目時,我總是想獲取 DashboardPageItem 的所有列表,而對於 DashboardPage 列表,每當我調用 Dashboard 條目時,我都不需要獲取列表,只是在某些情況下)。

我正在使用沒有 JPA 的 Hibernate,這是上述每個類的 hbm:

儀表板:

<class name="Dashboard" table="t_dashboard_das">
    <id name="id" column="das_id">
        <generator class="native"/>
    </id>
    <property name="name" column="das_name"/>
    <property name="description" column="das_description"/>
    <property name="visibility" column="das_visibility"/>

    <many-to-one name="createur" 
                 column="fk_sal_id"
                 foreign-key="sal_id"
                 not-null="false"
                 lazy="proxy"/>

    <many-to-one name="role" 
                 column="fk_rol_id"
                 foreign-key="rol_id"
                 not-null="false"
                 lazy="proxy"/>

    <bag table="t_dashboard_page_dpa" name="pages" inverse="true" lazy="true" cascade="all">
        <key column="fk_das_id" not-null="true" unique="false" foreign-key="das_id"/>
        <one-to-many class="com.dashboard.entity.DashboardPage"></one-to-many>    
    </bag>
</class>

儀表盤頁面:

<class name="DashboardPage" table="t_dashboard_page_dpa">
    <id name="id" column="dpa_id">
        <generator class="native"/>
    </id> 

    <property name="name" column="dpa_name"/>
    <property name="index" column="dpa_index"/>
    <property name="model" column="dpa_model"/>

    <many-to-one name="dashboard" 
                 column="fk_das_id"
                 foreign-key="das_id"
                 not-null="false"
                 lazy="proxy"/>

    <bag table="t_dashboard_page_item_dpi" name="dashboardPageItems" inverse="true" lazy="true" cascade="all">
        <key column="fk_dpa_id" not-null="true" unique="false" foreign-key="dpa_id"/>
        <one-to-many class="com.dashboard.entity.DashboardPageItem"></one-to-many>    
    </bag>             
</class>

儀表板頁面項:

<class name="DashboardPageItem" table="t_dashboard_page_item_dpi">
    <id name="id" column="dpi_id">
        <generator class="native"/>
    </id> 

    <property name="position" column="dpi_position"/>

    <many-to-one name="dashboardPage" 
                 column="fk_dpa_id"
                 foreign-key="dpa_id"
                 not-null="false"
                 lazy="proxy"/>

    <many-to-one name="widget" 
                 column="fk_wid_id"
                 foreign-key="wid_id"
                 not-null="false"
                 lazy="proxy"/>

</class>

我該如何解決這個問題?

編輯 :

這就是我檢索Dashboard

this.dashboard = dashboardService.trouver(idDashboard);

這將調用:

 public K get(int id) {
        if(id == 0) return null;
        return  (K) getSessionFactory().getCurrentSession().get(getClasse(),id);               
    }

其中KDashboard

理想情況下,您不想將休眠代理發送到您的 JSF 托管 bean(將它們打包到 DTO 中並進行處理)。

但是關於您當前的情況,我建議創建新的服務方法來更新儀表板(首先它會合並儀表板以使其由持久提供者管理):

@Transactional
public void updateDashboard(Dashboard dashboard, DashboardPageItem dashboardPageItem){
      Dashboard managedDashboard = session.merge(dashboard);
       for (DashboardPage dp : managedDashboard .getPages()) {
         DashboardPage managedDp = session.merge(dp);
        if (managedDp.getIndex() == pageIndex) {
            dashboardPageItem.setDashboardPage(managedDp);
            managedDp.getDashboardPageItems().add(dashboardPageItem);
        }
       }

       session.merge(managedDashboard);
 }

然后從您的托管 bean 中調用:

dashboardService.updateDashboard(dashboard, dashobardPageItem)

因此,您將始終在事務上下文中處理您的實體(我建議在大多數情況下這樣做)。

所以這里的問題是你想在事務之外訪問一個惰性集合。

有多種方法可以解決此問題。

  1. 訪問事務中的惰性集合
  2. 直接在查詢中獲取惰性集合

使用第一種方法,您將解決問題,但是它可能存在性能問題。

首選方式是第二種。

您可以在此處閱讀更多相關信息: https : //arnoldgalovics.com/lazyinitializationexception-demystified/

我真的建議閱讀整篇文章,因為它會澄清你腦海中的很多事情。

在您的儀表板實體中,請設置 lazy=false。 默認情況下,惰性被休眠標記為真。

我認為這是因為您不在交易環境中。 如果您使用的是 spring 或 cdi,也許您應該在類上添加 @Transactional。 或者@Stateless 如果你使用的是 ejb

暫無
暫無

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

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