Jon Kruger
Jon Kruger

Reputation: 4069

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 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.)

Upvotes: 2

Views: 1954

Answers (6)

Michael
Michael

Reputation: 1421

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.

Upvotes: 1

SideFX
SideFX

Reputation: 839

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

Upvotes: 0

KLE
KLE

Reputation: 24159

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.

Upvotes: 3

Jamie Ide
Jamie Ide

Reputation: 49261

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.

Upvotes: 1

Aaron Fischer
Aaron Fischer

Reputation: 21211

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

Upvotes: 1

DigitalNomad
DigitalNomad

Reputation: 428

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.

Upvotes: 2

Related Questions