Reputation: 4069
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
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
Reputation: 839
You could use an interceptor and then override the FindDirty method.
Upvotes: 0
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:
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
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
Reputation: 21211
Can you just remove the property you use to store this manually fetched data from NHibernates tracking?
Upvotes: 1
Reputation: 428
Expanding on KLEs answer, I would:
At that point I believe that NHibernate will recognize everything as clean.
Upvotes: 2