"Revert changes with the state of my first load" is what the user
thinks when she has changed an entity, but regrets. Thus wants to
cancel. However, she doesn't want to be punished by another database
hit. I'm sure many other people decide in this case to start a new
session or evict the object graph and get it again. All to me sound
like a half-baked solution for reasons I've mentioned before. Another
half-baked solution is to say that you only change the entities once
you're 100% sure (no, I want to "commit" once I'm 100% sure).

Having said all this, what I want to reach here, completely fits in
how I want my application to work. I think it is compatible with UoW
and all those other fancy design patterns. This is clearly a missing
feature to me. Therefore, I was really hoping for a technical
satisfying answer, rather than advocating that I'm doing is something
which is not written in one of the tutorials.

So, please... does anyone know how I could do this trick of reverting
changes in a graph?

On May 4, 7:32 pm, Fabio Maulo <[email protected]> wrote:
> There is something saying me that your problem is in another place.
> "Revert changes with the state of my first load"..... mmmmm
>
> On Tue, May 4, 2010 at 3:05 PM, tz 
> <[email protected]>wrote:
>
> > Thanks for confirming that. I silently started guessing that the
> > Refresh method shouldn't be what I should use. I started writing my
> > own "RevertChanges" on a graph, but I'm stuck on how to evict
> > collections (plus the attached pending deletes/adds). See my code
> > below:
>
> >    public static class ISessionExtensions
> >    {
> >        public static void RevertChanges(this ISession session, object
> > obj)
> >        {
> >            var source = session as IEventSource;
> >            var action = new RevertChangesCascadingAction();
>
> >            action.RevertChanges(source, obj);
> >        }
>
> >        private class RevertChangesCascadingAction : CascadingAction
> >        {
> >            public override void Cascade(IEventSource session, object
> > child, string entityName, object anything, bool
> > isCascadeDeleteEnabled)
> >            {
> >                DoRevert(session, child);
> >            }
> >            public override IEnumerable
> > GetCascadableChildrenIterator(IEventSource session, CollectionType
> > collectionType, object collection)
> >            {
> >                var coll = collection as
> > NHibernate.Collection.IPersistentCollection;
> >                var collectionEntry =
> > session.PersistenceContext.GetCollectionEntry(coll);
>
> >                // TODO: HELP!!!
> >                //session.Evict(collection);
> >                //collectionEntry.LoadedPersister.Recreate(coll,
> > collectionEntry.LoadedKey, session);
>
> >                // evicts don't cascade to uninitialized collections
> >                return GetLoadedElementsIterator(session,
> > collectionType, collection);
> >            }
> >            public override bool DeleteOrphans
> >            {
> >                get { return false; }
> >            }
> >            public override bool PerformOnLazyProperty
> >            {
> >                get { return false; }
> >            }
>
> >            protected void DoRevert(IEventSource session, object obj)
> >            {
> >                EntityEntry entityEntry = GetEntityEntry(session,
> > obj);
>
> >                IEntityPersister persister = entityEntry.Persister;
> >                EntityMode mode = persister.GuessEntityMode(obj) ??
> > EntityMode.Poco;
> >                persister.SetPropertyValues(obj,
> > entityEntry.LoadedState, mode);
> >            }
>
> >            protected EntityEntry GetEntityEntry(IEventSource session,
> > object obj)
> >            {
> >                IPersistenceContext context =
> > session.PersistenceContext;
>
> >                if (obj is ValueType)
> >                    return null;
>
> >                if (context.IsEntryFor(obj) == false)
> >                    return null;
>
> >                EntityEntry entityEntry = context.GetEntry(obj);
> >                return entityEntry;
> >            }
>
> >            public void RevertChanges(IEventSource session, object
> > obj)
> >            {
> >                EntityEntry entityEntry = GetEntityEntry(session,
> > obj);
>
> >                DoRevert(session, obj);
>
> >                session.PersistenceContext.IncrementCascadeLevel();
> >                try
> >                {
> >                    new Cascade(this, CascadePoint.AfterUpdate,
> > session).CascadeOn(entityEntry.Persister, obj);
> >                }
> >                finally
> >                {
>
> > session.PersistenceContext.DecrementCascadeLevel();
> >                 }
> >            }
> >        }
> >    }
>
> > On Apr 30, 7:55 pm, Jason Dentler <[email protected]> wrote:
> > > Confirmed it with Fabio: "Refresh is an explicit hit to DB"
>
> > > On Fri, Apr 30, 2010 at 8:35 AM, tz <
> > [email protected]>wrote:
>
> > > > * Transaction over a read didn't help (see reply on Jason Dentler)
> > > > * Second level cache is for sharing data across transactions
>
> > > > On Apr 30, 12:24 pm, John Davidson <[email protected]> wrote:
> > > > > It does not matter what the UoW pattern says about data read. You
> > > > _REALLY_
> > > > > need to put a read action in a NHibernate transaction if you want to
> > > > improve
> > > > > performance. Not having your reads in a transaction may be why you
> > need a
> > > > > second level cache (to compensate for not following the specified
> > rules).
> > > > > Most of the transactional databases now wrap a read action in an ACID
> > > > > transaction on their own, if the request is not already in a
> > transaction
> > > > -
> > > > > this activity by the database takes more time and resource than if it
> > is
> > > > > done in the application with NHibernate and UoW.
>
> > > > > John Davidson
>
> > > > > On Fri, Apr 30, 2010 at 7:14 AM, tz <
> > > > [email protected]>wrote:
>
> > > > > > Thanks for the reply. See my comments inline
>
> > > > > > On Apr 29, 8:26 pm, Jason Meckley <[email protected]> wrote:
> > > > > > > I would approach the problem in a completely different manner.
> > > > > > > 1. no long running sessions
> > > > > > > 2. only use 2nd level cache in edge cases as a last resort
> > > > > > > 3. for multi-step operations/commands I would use an intermediate
> > DTO
> > > > > > > to store updates. When the user clicks "save" is when i would
> > alter
> > > > > > > the domain objects. this makes undoing changes much easier.
> > simply
> > > > > > > abandon the DTO.
>
> > > > > > I'm not sure whether you do understand my question, but I can't
> > relate
> > > > > > any of your reply to my question. I also don't agree with what
> > you're
> > > > > > saying...
> > > > > > * I don't know what "no long running sessions" would solve for my
> > > > > > issue. All these things you're proposing are a "very complex" way
> > to
> > > > > > do Evict/Load on the same session.
> > > > > > * 2nd level cache is for performance reasons. The issue I'm posting
> > > > > > about is also for performance reasons. So, this cache stays
> > > > > > * Why would I do any object dirty management myself, if nHibernate
> > can
> > > > > > do it for me.
>
> > > > > > > if you do continue down this path are all your session calls
> > > > happening
> > > > > > > within a transaction? Proper use of NH dictates that all
> > operations,
> > > > > > > both read and write, should happen within at transaction. This is
> > > > > > > critical for client POIDs, proper UOW management and 2nd level
> > cache.
>
> > > > > > Again, no answer on my question. Even more, I don't agree with
> > you...
> > > > > > * UoW pattern doesn't say that a read should be in a ACID
> > transaction.
> > > > > > UoW itself is a "business transaction" implementation, which is
> > based
> > > > > > optimistic concurrency ideologies (meaning that you shouldn't keep
> > an
> > > > > > ACID transaction open between the reads and the writes).
>
> > > > > > What I want is simply a Update() which does what Evict/Load does,
> > but
> > > > > > not with giving me a new instance. That's all I'd want to know. I
> > know
> > > > > > nH keeps the original state in the session (and the second level
> > > > > > cache), so it shouldn't be that difficult I assume.
>
> > > > > > > On Apr 29, 2:05 pm, tz <[email protected]>
> > wrote:
>
> > > > > > > > Hi guys,
>
> > > > > > > > I'm working with a long running session which contains all my
> > > > required
> > > > > > > > data. Further, I use level 2 cache intensively, to cache that
> > > > > > > > information. I let my user edit this data directly using UI
> > > > controls.
>
> > > > > > > > The user can decide to cancel the modifications, which I though
> > I'd
> > > > > > > > easily solve with performing a ISession.Refresh(..) on the
> > > > aggregate
> > > > > > > > root of the changed entity.
>
> > > > > > > > However, it turns out that Refresh(...) always goes to the
> > database
> > > > to
> > > > > > > > refetch the data, even if the data is available in second level
> > > > cache
> > > > > > > > (tested that the data is there using a second ISession, which
> > > > returned
> > > > > > > > the data without a database hit).
>
> > > > > > > > Is there a way to refresh entity from data in the second level
> > > > cache?
>
> > > > > > > > I don't want to use Evict+Load, as I will then get a new
> > instance
> > > > > > > > (Refresh(...) updates the same instance).
>
> > > > > > > > Thanks
>
> > > > > > > > --
> > > > > > > > You received this message because you are subscribed to the
> > Google
> > > > > > Groups "nhusers" group.
> > > > > > > > To post to this group, send email to [email protected].
> > > > > > > > To unsubscribe from this group, send email to
> > > > > > [email protected]<nhusers%[email protected]­>
> > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > ­>
> > > > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > <nhusers%252bunsubscr...@googlegroup­s.com>
> > > > ­>
> > > > > > .
> > > > > > > > For more options, visit this group athttp://
> > > > > > groups.google.com/group/nhusers?hl=en.
>
> > > > > > > --
> > > > > > > You received this message because you are subscribed to the
> > Google
> > > > Groups
> > > > > > "nhusers" group.
> > > > > > > To post to this group, send email to [email protected].
> > > > > > > To unsubscribe from this group, send email to
> > > > > > [email protected]<nhusers%[email protected]­>
> > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > ­>
> > > > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > <nhusers%252bunsubscr...@googlegroup­s.com>
> > > > ­>
> > > > > > .
> > > > > > > For more options, visit this group athttp://
> > > > > > groups.google.com/group/nhusers?hl=en.- Hide quoted text -
>
> > > > > > > - Show quoted text -
>
> > > > > > --
> > > > > > You received this message because you are subscribed to the Google
> > > > Groups
> > > > > > "nhusers" group.
> > > > > > To post to this group, send email to [email protected].
> > > > > > To unsubscribe from this group, send email to
> > > > > > [email protected]<nhusers%[email protected]­>
> > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > ­>
> > > > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > <nhusers%252bunsubscr...@googlegroup­s.com>
> > > > ­>
> > > > > > .
> > > > > > For more options, visit this group at
> > > > > >http://groups.google.com/group/nhusers?hl=en.
>
> > > > > --
> > > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "nhusers" group.
> > > > > To post to this group, send email to [email protected].
> > > > > To unsubscribe from this group, send email to
> > > > [email protected]<nhusers%[email protected]­>
> > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > ­>
> > > > .
> > > > > For more options, visit this group athttp://
> > > > groups.google.com/group/nhusers?hl=en.- Hide quoted text -
>
> > > > > - Show quoted text -
>
> > > > --
> > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "nhusers" group.
> > > > To post to this group, send email to [email protected].
> > > > To unsubscribe from this group, send email to
> > > > [email protected]<nhusers%[email protected]­>
> > <nhusers%[email protected]<nhusers%252bunsubscr...@googlegroup­s.com>
> > ­>
> > > > .
> > > > For more options, visit this group at
> > > >http://groups.google.com/group/nhusers?hl=en.
>
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > "nhusers" group.
> > > To post to this group, send email to [email protected].
> > > To unsubscribe from this group, send email to
> > [email protected]<nhusers%[email protected]­>
> > .
> > > For more options, visit this group athttp://
> > groups.google.com/group/nhusers?hl=en.- Hide quoted text -
>
> > > - Show quoted text -
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "nhusers" group.
> > To post to this group, send email to [email protected].
> > To unsubscribe from this group, send email to
> > [email protected]<nhusers%[email protected]­>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/nhusers?hl=en.
>
> --
> Fabio Maulo
>
> --
> You received this message because you are subscribed to the Google Groups 
> "nhusers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group 
> athttp://groups.google.com/group/nhusers?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en.

Reply via email to