2010-06-22 78 views
1

我有一個對象,我保持對另一個對象的關係:使用臨時對象將導致瞬時對象異常

public class Foo { 
    public Bar Bar { get; set; } 
} 

在映射我參考吧,以我能保持的關係 - 我不想父對象到子更新屬性,只是關係存在:

References(x => x.Bar, "BarId") 
    .Cascade.None(); 

在UI層我使用屬性是不是底層主鍵創建關係

item.Bar = new Bar { Code = "123" }; 

在存儲庫層I水合對象,如果沒有它的主鍵填充:

if(item.Bar.Id == null) 
{ 
    item.Bar = barRepository.RetrieveByCode(item.Bar.Code); 
} 

當我RetrieveByCode線延伸(這是一個Criteria.UniqueResult下蓋)我得到一個TransientObjectException告訴我「對象引用一個未保存的瞬態實例 - 在沖洗前保存瞬態實例」。

當我運行相同的代碼路徑而不創建臨時Bar對象時,它的工作原理。看起來,作爲臨時對象創建的Bar被NHibernate追蹤,但我希望它忘記它曾經存在,因爲它只是一個佔位符。

有關如何實現此目的的任何想法?

UPDATE:對此做了一些更多的測試,它似乎是Foo中導致問題的更改跟蹤。如果我在檢索它之後調用Session.Evict(item),但在進行任何更改之前,然後在完成後使用Session.Update(item)重新附加該對象,似乎可以工作,但是它更新了不是我想要的 - 我只想管理這種關係。

UPDATE 2:我將FlushMode從Auto更改爲Commit。它似乎禁用了對該對象的任何臨時更改的排隊。在進一步研究了NH行爲後,似乎Update更像「重新連接」呼叫而不是明確的「立即更新」呼叫。

UPDATE 3:它看起來不斷變化FlushMode導致需要幾個操作步驟的事務的其他問題。我回到了嘗試另一種方法:

if(item.Bar.Id == null) 
{ 
    var barCode = item.Bar.Code; 
    item.Bar = null; 
    item.Bar = barRepository.RetrieveByCode(barCode); 
} 

回答

0

爲什麼你想要它的工作方式?爲什麼不直接設置item.Bar使用檢索到的酒吧對象:

item.Bar = barRepository.RetrieveByCode("123"); 

您可能能夠使用Load您當前的工作模式,使:

if(item.Bar.Id == null) 
{ 
    var bar = barRepository.RetrieveByCode(item.Bar.Code); 
    item.Bar = session.Load<Bar>(bar.Id); 
} 
+0

UI層不關心自己如何對象被持久化。它告訴域名服務在Foo和Bar之間建立關係。域服務調用各種存儲庫來保存適當的對象。 Load示例的挑戰是,當它嘗試調用Criteria.UniqueResult時,在RetrieveByCode期間拋出了TransientObjectException,所以我將無法進入Load調用。 – 2010-06-22 15:00:37

+0

存儲庫應該共享一個ISession,以便他們可以參與事務。我不明白爲什麼標準查詢會拋出異常;你可以發佈代碼嗎? – 2010-06-22 17:43:13

+0

它可能會拋出,因爲它正在沖洗並發現假Bar對象被引用。如果它是級聯的,它會堅持一個新的實例。整個用法是錯誤的。 – 2010-06-23 00:29:21