I come back to the separation of queries and commands. I think this
will go a long way to help alleviate the issue. NH deals with objects,
not tables/rows. the id of an object is a database artifact within the
domain model. that is why you evict by object rather than id.  I also
convert the sql query to domain logic. this would mean the object gets
updated first, then changes are persisted to the database. again
removing the issue of 2nd db hits and eviction.

This will be your best option to work with the concepts of NH, rather
than against them.

On Oct 1, 9:15 am, Yauhen <[email protected]> wrote:
> Let me clarify slightly :)
> Sometimes I have this sequence
> 1)
> session open
> session get (hit db)
> session update
> session get (hit db)
>
> and
> some times this one
> 2) session open
> session update
> session get (hit db)
>
> In 2nd case first session get (hit db) is missing.
> Command (session update ) lies inside separate method
> MessagesRepository.Delete.
> So I was thinking of some type of uniform. So in both cases I will
> need to just call MessagesRepository.GetDetails.
> But in 1st this is not true. Because I will need to do Evict. I was
> thinking to place it inside MessagesRepository.Delete.
> But it is not possible to do this by id. Of course I could write to
> methods - MessagesRepository.Delete(id),
>  MessagesRepository.Delete(entity) and in 2nd do Evict. 2nd will be
> used in 1) sequence of commands. As I understand the most simple way
> to
> do 1) without evict is using separate sessions. But I was thinking
> before that sharing the same session will be more correct for
> performance.
> So my implementation was based on NHibernate Best Practices with
> ASP.NET, 1.2nd Ed.(http://www.codeproject.com/KB/architecture/
> NHibernateBestPractices.aspx)
>
> On Oct 1, 4:01 pm, Jason Meckley <[email protected]> wrote:
>
> > in that scenario there is no need to evict, because no entities have
> > been loaded. it may be that execute update works like save/update/
> > delete/etc. calling the method queues the command. it's not actually
> > executed until the session is flushed. example
>
> > session open
> > session update (update is queued)
> > session get (hit db)
> > tx.commit/session.flush (update is executed)
>
> > if that's the case it would explain why you are getting "stale" data.
>
> > Something else to consider is the session/unit of work boundaries and
> > practice of command query separation. I have used this with great
> > success without fail. In the context of NH  a session should have the
> > purpose of getting data (query) or modifing data (command), not both.
> > in the context we described we have queries and commands.
>
> > at a minimum this should work
> > using(var session = factory.OpenSession())
> > {
> >    using(var tx = session.BeginTransaction())
> >    {
> >          session....ExecuteUpdate();
> >          tx.Commit(); //omitting rollback code, but it should be there
> >    }
> >    using(var tx = session.BeginTransaction())
> >    {
> >          var entity session..Get<Entity>(id);
> >          Display(entity);
> >          tx.Commit(); //omitting rollback code, but it should be there
> >    }
>
> > }
>
> > typically I wouldn't write the code this way either, unless I was
> > stuck using webforms. instead I would write it like this
> > using(var session = factory.OpenSession())
> > using(var tx = session.BeginTransaction())
> > {
> >    session....ExecuteUpdate();
> >    tx.Commit(); //omitting rollback code, but it should be there
>
> > }
>
> > using(var session = factory.OpenSession())
> > using(var tx = session.BeginTransaction())
> > {
> >    var entity session..Get<Entity>(id);
> >    Display(entity);
> >    tx.Commit(); //omitting rollback code, but it should be there
>
> > }
>
> > where each of those would be it's own request. in web MVC it's
> > referred to as Post-Redirect-Get. the concept of query command
> > separation would apply to rich clients or messsaging as well. the
> > implementation may look different though.
>
> > On Oct 1, 3:14 am, Yauhen <[email protected]> wrote:
>
> > > I am speaking about your scenario:
> > > session open
> > > session get (hit db)
> > > session update
> > > session evict (if you don't evict get pulls for 1st level cache)
> > > session get (hit db)
>
> > > I want that it looks like
> > > session open
> > > session update
> > > session evict (by it without database hit)
> > > session get (hit db)
>
> > > So I want some way to evict from 1st level cache by id.
>
> > > On Sep 30, 8:26 pm, Jason Meckley <[email protected]> wrote:
>
> > > > I don't follow. may be I should back up.
> > > > what are you doing now? is it the code your originally posted? if not
> > > > please post the actual code.
> > > > what is happening?
> > > > what do you want/expect to happen?
> > > > what do you mean by cache? 1st level cache. also known as the identity
> > > > map. or are you referring to 2nd level cache?
> > > > I assume the 1st level cache, since you don't have caching enabled in
> > > > the mapping.
>
> > > > if the entity exists in the 1st level cache and you query the
> > > > database, but the object already exists in the cache the cached object
> > > > is returned, not the database object. have you run your application
> > > > through nhprof? this will give you an excellent idea of what's going
> > > > on.
>
> > > > On Sep 30, 11:25 am, Yauhen <[email protected]> wrote:
>
> > > > > Are there any way to do without additional hit on database? For
> > > > > example to make evict by id?
> > > > > Because first get seen to me redundant. I need only updated entity not
> > > > > original. And method should be as
>
> > > > > session get (hit db)
> > > > > session update
> > > > > session evict (if you don't evict get pulls for 1st level cache)
>
> > > > > On Sep 30, 5:58 pm, Jason Meckley <[email protected]> wrote:
>
> > > > > > if the next call comes from the same session, then you need to evict
> > > > > > the object. example:
> > > > > > session open
> > > > > > session get (hit db)
> > > > > > session update
> > > > > > session evict (if you don't evict get pulls for 1st level cache)
> > > > > > session get (hit db)
>
> > > > > > if the the call comes from a completely different session then you
> > > > > > don't need to do anything.
> > > > > > session 1: open
> > > > > > session 2: open
> > > > > > session 2: get (hit db)
> > > > > > session1: update
> > > > > > session2: get (1st level cache)
> > > > > > this is by design
>
> > > > > >  if you are expecting this:
> > > > > > session 1: open
> > > > > > session 2: open
> > > > > > session 2: get (hit db)
> > > > > > session1: update
> > > > > > session2: get (hit db)
> > > > > > ...
> > > > > > it won't, not without evicting anyway. that is by design. there are 
> > > > > > 3
> > > > > > options to handle that
> > > > > > 1. pessimistic concurrency (lock the database row)
> > > > > > 2. optimistic concurrency (versioning)
> > > > > > 3. call evict on session 2
>
> > > > > > typically #2 provides better performance. it requires you to handle
> > > > > > the StaleObjectException. #1 can result in command timeouts, so you
> > > > > > would need to handle them as well. #3 goes against how NH is 
> > > > > > designed
> > > > > > to operate. it's possible, but not advisable. also you cannot
> > > > > > guarantee evict is called before session 1 update.
>
> > > > > > On Sep 30, 10:32 am, Yauhen <[email protected]> wrote:
>
> > > > > > > I simply need invalidate cache. So next call not get value fro 
> > > > > > > cache
> > > > > > > but from real database.
>
> > > > > > > On Sep 30, 5:27 pm, Roger Kratz <[email protected]> wrote:
>
> > > > > > > > I'm not sure I understand but...
>
> > > > > > > > << [...] Session is the same betwwen calls. [...]>>
> > > > > > > > << [...] query.ExecuteUpdate(); [...] >>
>
> > > > > > > > Are you expecting your call to ExecuteUpdate to update the 
> > > > > > > > state inside your ISession? I don't think that will work.
>
> > > > > > > > Session keeps a first level cache. The state of this cache 
> > > > > > > > won't be updated when calling ExecuteUpdate AFAIK - no entities 
> > > > > > > > are returned.
>
> > > > > > > > /Roger
>
> > > > > > > > -----Original Message-----
> > > > > > > > From: [email protected] 
> > > > > > > > [mailto:[email protected]] On Behalf Of Yauhen
> > > > > > > > Sent: den 30 september 2010 16:10
> > > > > > > > To: nhusers
> > > > > > > > Subject: [nhusers] Re: NHibernate cache
>
> > > > > > > > so nobody has ideas?
>
> > > > > > > > On Sep 28, 12:50 pm, Yauhen <[email protected]> wrote:
> > > > > > > > > I have found very strange effect when using nhibernate.
> > > > > > > > > I am trying to do one clever update operation. Then read 
> > > > > > > > > saved data
> > > > > > > > > from database.
> > > > > > > > > Operations are mostly based on sql queries. In database data 
> > > > > > > > > are ok.
> > > > > > > > > But by some strange reason nhibernate uses cached old data.
> > > > > > > > > Operations are described like following:
> > > > > > > > > <class name="Message"  table="Messages" >
> > > > > > > > >                 <id name="Id" type="Int32" column="Id">
> > > > > > > > >                         <generator class="identity"/>
> > > > > > > > >                 </id>
> > > > > > > > >                 <property name="Subject" column="Subject" 
> > > > > > > > > type="String"/>
> > > > > > > > >                 <property name="CategoryId" 
> > > > > > > > > column="CategoryId" type="Int32"/>
>
> > > > > > > > > <sql-query name="Message.Delete">
> > > > > > > > >     <synchronize table="Messages"/>
> > > > > > > > >     UPDATE Messages
> > > > > > > > >     SET CategoryId = (  /* long select to decide to which 
> > > > > > > > > category to
> > > > > > > > > move*/
> > > > > > > > >                                )
> > > > > > > > >      WHERE Id = :messageId
> > > > > > > > >   </sql-query>
>
> > > > > > > > >  <sql-query name="Message.GetDetails">
> > > > > > > > >     <return alias="msg" class="Message"/>
> > > > > > > > >         SELECT  {msg.*}
> > > > > > > > >         FROM Messages {msg}
> > > > > > > > >         WHERE msg.Id = :messageId
> > > > > > > > >   </sql-query>
>
> > > > > > > > > when calling delete/update query I use syntax like following
> > > > > > > > >  using (ITransaction trans = _session.BeginTransaction())
> > > > > > > > >             {
> > > > > > > > >                 IQuery query =
> > > > > > > > > _session.GetNamedQuery("Message.Delete");
> > > > > > > > >                 query.SetParameter<IdT>(paramName, id);
> > > > > > > > >                 query.ExecuteUpdate();
> > > > > > > > >                 trans.Commit();
>
> ...
>
> read more »

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