开发者

NHibernate: is there a way to mark an object as NOT dirty?

I have a situation where I need to load part of an object graph using custom SQL (for performance reasons). So I load up this collection using my custom SQL (ISession.CreateSQLQuery()) and then I开发者_如何学C assign that list to a property on another entity object.

The problem is that when I assign the list to the property, it makes that entity dirty along with all of the objects in the list, so when I go to save the object, it does hundreds of queries to save the entire list. Is there a way that I can specify that an object is NOT dirty (after I load it up myself)?

(Yeah, I know I could turn off cascade="save-update", but I really don't want to have to do that if I can avoid it.)


I think there is a functionality to evict an entity.

That means it is not connected to NHibernate anymore.


UPDATED after Jon's various comments:

  • If you want NHibernate to manage the object, ie detect if it is dirty, then keep it managed.
  • If not, Evict() it, it won't be managed. You can still save it manually and so on, it's just that it won't be done automatically for you.

I don't see any middle ground, between automatic and manual...

Note that you can still persist in various ways, like saving manually the parent entity, a Set of child entities and so on... Many things are still possible.


Expanding on KLEs answer, I would:

  1. Evict() the parent entity
  2. Load the child list
  3. Attach the list of children to the parent entity
  4. Merge() the whole thing back into nHibernate

At that point I believe that NHibernate will recognize everything as clean.


Can you just remove the property you use to store this manually fetched data from NHibernates tracking?


Assuming that you are not persisting the property that the list is assigned to, you can remove that property from the NHibernate mapping. I haven't tested this, but my expectation is that assigning to that property would not cause IsDirty() to return true.

EDIT: Ok, try try this. Load the object from an IStatelessSession, call your custom SQL and assign the property. Then Lock the object into a new ISession and continue working with it. I think the Lock will cascade to child objects if your cascade setting is all or all-delete-orphan. If Lock does not cascade then you will have to manually walk the object graph.


I don't remember where I got this from, but I have a class of Session extensions, one of which is this:

public static Object GetOriginalEntityProperty(this ISession session, Object entity, String propertyName)
{

    ISessionImplementor sessionImpl = session.GetSessionImplementation();

    IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;

    EntityEntry oldEntry = persistenceContext.GetEntry(entity);



    if ((oldEntry == null) && (entity is INHibernateProxy))
    {

        INHibernateProxy proxy = entity as INHibernateProxy;

        Object obj = sessionImpl.PersistenceContext.Unproxy(proxy);

        oldEntry = sessionImpl.PersistenceContext.GetEntry(obj);

    }

    if (oldEntry == null)  // I'm assuming this means the object is transient and that this is the way to treat that
        return false;

    String className = oldEntry.EntityName;

    IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);

    Object[] oldState = oldEntry.LoadedState;

    Object[] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);

    Int32[] dirtyProps = persister.FindDirty(currentState, oldState, entity, sessionImpl);

    Int32 index = Array.IndexOf(persister.PropertyNames, propertyName);



    Boolean isDirty = (dirtyProps != null) ? (Array.IndexOf(dirtyProps, index) != -1) : false;



    return ((isDirty == true) ? oldState[index] : currentState[index]);

}

If you get the original value using this method and assign it to the persistent property it will no-longer be dirty.


You could use an interceptor and then override the FindDirty method.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜