2010-06-22 82 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