使用临时对象会导致瞬态对象异常

时间:2010-06-22 14:25:17

标签: nhibernate nhibernate-mapping

我有一个对象,我与另一个对象保持关系:

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

在映射中我引用了Bar,我可以维护关系 - 我不希望父对象更新子进程中的属性,只是存在关系:

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

在UI层中,我使用不是基础主键的属性创建关系:

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

在存储库层中,如果对象没有填充主键,则会对其进行水合:

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

当我运行RetrieveByCode行(这是一个Criteria.UniqueResult)时,我得到一个TransientObjectException告诉我“对象引用一个未保存的瞬态实例 - 在刷新之前保存瞬态实例”为Bar类型。

当我运行相同的代码路径而不创建临时Bar对象时,它可以工作。似乎作为临时对象创建的Bar由NHibernate跟踪,但我希望它忘记它曾经存在,因为它只是一个占位符。

有关如何实现这一目标的任何想法?

更新:对此进行更多测试似乎是Foo中的更改跟踪导致了问题。如果我在检索后调用Session.Evict(item),但在进行任何更改之前使用Session.Update(item)重新附加对象后,它似乎工作,但它会更新不是的子对象我想要什么 - 我只想管理这段关系。

更新2 :我将FlushMode从Auto更改为Commit。它似乎已禁用对象的任何临时更改的排队。进一步研究NH行为后,似乎Update更像是“重新连接”调用,而不是明确的“立即更新”调用。

更新3 :看来更改FlushMode会导致需要多个操作步骤的事务的其他问题。我回过头来尝试另一种方法:

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

1 个答案:

答案 0 :(得分:0)

为什么你希望它以这种方式工作?为什么不使用检索到的Bar对象简单地设置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);
}