2011-09-08 54 views
1

我遇到了具有奇怪條件的懶惰初始化。休眠會話已不存在

  1. 事務:獲取持久對象的底層實體。
  2. 事務:獲取非持久對象的底層實體。
  3. 事務:合併一個持久對象。然後堅持 一個不持久化的對象拋出一個異常。

    javax.persistence.PersistenceException:org.hibernate.LazyInitializationException:無法初始化代理 - 沒有會話。

當堅持Person類的複雜對象時拋出。

public class Person { 
    protected List<Person> founders; 
    protected List<GeoObject> ownedGeoObjects; 
} 

public class GeoObject { 
    private List<Person> owners; 
    private Address address; //complex lazy-fetched structure of pre-defined persistent entities (country, city, etc.) 
} 

ownedGeoObjects和創始人可以由用戶創建或找到並添加到列表中作爲存在(持久性)。所有存在的和用戶創建的實體都存儲在事務之間的有狀態bean(人員字段)中。並完全取代他們分開的交易。然後堅持所有結構都來自commitPerson():如果ownedGeoObjects之一是持久的,另一種是不

@Stateful 
public class SessionManager { 

    private Person person; 

    private Person commitPerson(Person person) {  
     personManager.addPerson(person); 
     commitFounders(person.getFounders()); 
     commitGeoObjects(person);  
     return person; 
    } 

    private void commitFounders(List<Person> founders) throws ValidationError { 
     for (Person founder : founders) { 
     if (!founder.getPersistent()) { 
      personManager.addPerson(founder); 
     } 
     } 
    } 

    private void commitGeoObjects(Person person) throws ValidationError { 
     List<GeoObject> objects = person.getOwnedGeoObjects(); 
     for (GeoObject geoObject : objects) { 
     refetch(geoObject); //this is my workaround 
     geoObject.getOwners().add(person); //inverse relation   
     if (!geoObject.getPersistent()) { 
      geoObjectManager.addGeoObject(geoObject); 
     } else { 
      geoObjectManager.updateGeoObject(geoObject); 
     } 
     } 
    } 

} 

拋出異常。

at ru.vetrf.cerberus.ejb.GeoObjectManager.addGeoObject(GeoObjectManager.java:119) 

這條線是

addressManager.addAddress(geoObject.getAddress()); 

好像會話持久GeoObject的更新(合併)走了之後(一個不是永久GeoObject及其地址)。爲什麼會發生? 其他場景(一個存在,一個新的,多個存在,多個新)通過。 創始人名單不受此問題影響。

p.s.可以認爲添加/更新方法僅由持久/合併組成。

回答

1

這是一個問題,即您在事務之間移動具有未初始化代理的對象。這就是拋出這樣的錯誤的地方:當你訪問代理(例如延遲加載列表)時,何時加載對象的事務被關閉。

考慮一下,如果你真的需要延遲加載,如果是這樣,請確保所有代理平倉交易之前加載(FG person.getOwners()()大小)

+0

我沒有提到的是,收盤前每單獨轉換所有相關實體。但正如我所說的,當一個GeoObject實體持久化而另一個不持久時,問題就出現了。現在,作爲解決方法,我在每次添加/更新之前都會重新獲取GeoObject。 (我跳過它,GeoObject也有底層實體)。但我仍然不知道爲什麼我應該這樣做。 – user935629