2010-04-08 64 views
3

我已經在互聯網上看到過有關如何在保存/更新/刪除期間修復TransientObjectExceptions的帖子,但是在調用Criteria時,我遇到了這個問題。org.hibernate.TransientObjectException在Criteria.list()

我有兩個對象A和B. A有一個名爲b的字段,它是B類型的。在我的映射b中映射爲多對一。這一切都運行在一個更大的持久化框架中(該框架有點像核心數據),所以我沒有在我的hibernate映射中使用任何級聯,因爲級聯在更高級別上處理。

這是圍繞我的標準的有趣的代碼:

A a = new A(); 
B b = new B(); 
a.setB(b); 

session.save("B", b); // Actually handled by the higher level 
session.save("A", a); // framework, this is just for clarity 

// transaction committed and session closed 
... 
// new session opened 

Criteria criteria = session.createCriteria(A.class); 
criteria.add(Restrictions.eq("b", b)); 
List<?> objects = criteria.list(); 

基本上我尋找類型的所有對象,且ab等於B的特定實例(其實我試圖重組的查詢,使我傳遞b的id只是爲了確保b不會導致我的問題)。

這裏是發生堆棧跟蹤當我打電話criteria.list():

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: B 
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244) 
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:449) 
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:141) 
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1769) 
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1740) 
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1612) 
at org.hibernate.loader.Loader.doQuery(Loader.java:717) 
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270) 
at org.hibernate.loader.Loader.doList(Loader.java:2294) 
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2172) 
at org.hibernate.loader.Loader.list(Loader.java:2167) 
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119) 
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1706) 
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) 

這裏是我的映射:

<class entity-name="A" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" />
</class>

<class entity-name="B" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
</class>

人幫我弄清楚爲什麼我會在獲取期間獲得TransientObjectException?最好我想找到一個不依賴級聯的解決方案,因爲它們傾向於掩蓋更高級別框架中出現的問題。

+0

你可以顯示對象'b'來自你的代碼嗎?它是否持久? – 2010-04-08 20:54:05

+0

彼得,你是個天才!我保存b的會話早已不在這一點,所以我必須在新的會話中更新b,然後再根據條件調用list。請添加一個答案,以便我可以授予您信用額度。 – rancidfishbreath 2010-04-08 21:33:55

+0

感謝:-)我在此期間添加了我的答案。 – 2010-04-08 21:37:58

回答

1

問題在於b在另一個會話中是持久的,該會話已關閉,並且該查詢是在新會話中創建的。當會話關閉時,其持久性上下文中的所有對象都變爲分離。如果你想以後重新使用他們在另一個會話,你需要首先重新連接到該會話:

session.update(b); 

從Hibernate書中引用:

update()操作 在會議重新掛接分離的對象到持久化上下文並且 安排SQL UDPATE。休眠必須假定客戶端在分離時修改了 對象。(否則,如果您確定它未被修改,則 a lock()就足夠了。)當對話中的第二個事務提交時,持久化上下文自動刷新爲 ,並且任何 修改爲一次分​​離,現在持久對象與數據庫同步 。

saveOrUpdate()方法在實踐中是比update()更加有用, save(),或lock():在複雜的對話,你不知道,如果該項目在 分離狀態或者如果它是新的,短暫的,並且必須保存。當您的 不僅適用於單個實例,還希望重新掛接或保留已連接對象的網絡 並應用級聯選項時,saveOrUpdate()提供的自動 狀態檢測功能變得更加有用。

注意,也有merge()方法,用於當同一實體已經被加載到新的持久化上下文老脫管的實例可以被重新裝上了。在這種情況下,您有兩個物理上不同的實例代表相同的實體,因此應合併它們以避免NonUniqueObjectException

+0

再次感謝彼得!直到你指出這一點,我一直在爲此爭論不休。 – rancidfishbreath 2010-04-08 21:40:31

+0

當我嘗試瞭解決方案時,我遇到了同樣的問題我開始得到:}:org.springframework.dao.DuplicateKeyException:具有相同標識符值的不同對象已與會話相關聯: – 2015-02-09 09:15:26

0

完成同樣的另一個簡單方法是使用屬性cascade = all在父類映射內的子類的集合映射中使用。下面是映射的樣子

<class entity-name="A" lazy="false"> 
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" /> 
<id type="long" column="id"> 
<generator class="native" /> 
</id> 
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" cascade="all" /> 
</class> 

<class entity-name="B" lazy="false"> 
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" /> 
<id type="long" column="id"> 
<generator class="native" /> 
</id> 
</class> 
+0

除了我在問題中明確指出出於在問題中提到的原因,我不想使用級聯。 – rancidfishbreath 2010-05-26 17:08:48

+0

我同意並尊重您在頂部的解釋。但是,由於可以通過網絡進行博客搜索,我想提出一個不同的場景,當級聯不能由代碼處理時,可以通過這種方式完成。也會修改我的部分。 – 2010-05-30 02:08:10

0

既然你插入數據,如堅持(),保存()在hibernate..But上述錯誤是你只是不合並()等可以執行方法更新信息。

相關問題