开发者

Using Temporary Objects causes Transient Object Exception

I have an object where I maintain a relationship to another object:

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

In the mapping I reference Bar to that I can maintain the relationship - I don't want the parent object to update properties in the child, just the existence of the relationship:

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

In the UI layer I create the relationship using a property which is not the underlying primary key:

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

In the repository layer I hydrate the object if it doesn't have the primary key populated:

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

When I the RetrieveByCode line runs (开发者_如何学Gowhich is a Criteria.UniqueResult under the covers) I get a TransientObjectException telling me that "the object references an unsaved transient instance - save the transient instance before flushing" for the Bar type.

When I run the same code path without creating the temporary Bar object it works. It appears that the Bar created as a temporary oject is tracked by NHibernate, yet I want it to forget that it ever existed as it is only a placeholder.

Any thoughts on how to achieve this?

UPDATE: Doing some more testing on this it seems to be the change tracking in Foo that is causing trouble. If I call Session.Evict(item) after retrieving it, but before making any changes and then re-attach the object using Session.Update(item) after I am done it seems to work, however it updates the child objects which is not what I want - I only want to manage the relationship.

UPDATE 2: I changed the FlushMode from Auto to Commit. It seems to have disabled the queueing of any interim changes to the object. Having researched NH behavior a bit further it seems that Update works more like a "re-attach" call rather than an explicit "update now" call.

UPDATE 3: It appears changing FlushMode caused other issues with transactions that required several operational steps. I reverted back to try another approach:

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


Why do you want it to work that way? Why not simply set item.Bar using the retrieved Bar object:

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

You might be able to make your current pattern work using Load:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜