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...@googlegroups.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...@googlegroups.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...@googlegroups.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.
>
> --
> 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.- 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].
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en.