1) How heavy is a session? If every session must establish a
connection to the database, then I'd expect there's going to be a fair
amount of overhead and we're not going to want to create them very
often.
2) How long, in seconds (for example), seems like a reasonable
lifetime for a session? I realize there may be no reasonable answer to
this question as it could depend on frequency and distribution of
reads and writes. Right now the application is littered with session
create statements because at each of those code locations a lazy load
exception has been encountered at some time in the past. The current
remedy is to call session.Load() on the object, although from what I
read in the docs tonight, it looks like the appropriate way is to call
session.Update().
As I'm new to the application, I'm not sure if the lazy load
exceptions occur because of a session timeout or an explicit close or
dispose. If it's happening because of a timeout, then we might need to
follow something like the session-per-request-with-detached-objects
pattern (http://community.jboss.org/wiki/Sessionsandtransactions). If
the sessions are not too heavy nor too short-lived, I'm considering
scoping sessions (e.g.CallSessionContext) to a particular dialog or
control, but I have much to learn before making a formal suggestion.
Thanks for any help you can offer.
--Kaleb
This is a matter of connection pooling. The connection can live longer
than the ISession. An ISession may even release the connection between
transactions.
Thanks for the link to Ayende's article, I'll definitely read through
it (and ask questions).
> nh session != db connection.
> sessions are cheap so create them as needed. the session doesn't
> create the connection until it's actually needed. the connection will
> then be disposed of when it's no longer needed.
[... snip ...]
> there are some common approaches to scoping session:
> web: session per request
> fat client: session per form
Since sessions are disparate from database connections, and forms may
be long-lived, I assume that I don't need to worry about the passage
of time, i.e. user think-time. As long as the NHibernate session
object stays active even lazy loaded and proxied objects will be able
to use their parent session to do any necessary work or make necessary
queries.
> service/background: session per thread
>
> lazy loading requires an active session for example
> this works
> //open session
> var entity = session.Get<Entity>(id);
> var reference = entity.ReferencedEntity;
> //close session
>
> this does NOT work
> //open session
> var entity = session.Get<Entity>(id);
> //close session
> var reference = entity.ReferencedEntity;
We've been using session.Load(Type t, object id) instead of Get. Aside
from the exception difference, it looks like there's a difference in
how it handles proxies. From a cursory glance through reflector on an
older nhibernate assembly, it looks like Get doesn't allow the
creation of proxies, but what's the exact difference?
> http://www.amazon.com/NHibernate-3-0-Cookbook-Dentler-Jason/dp/184951304X/ref=sr_1_1?ie=UTF8&s=books&qid=1292508288&sr=1-1
> Nhibernate 3.0 Cookbook was recently released and has great reviews.
> This would be a great place to start learning NH.
I'll consider it, thanks. I generally don't like the "cookbook" style
books, but this appears to explain well and provide sufficient
background.
> depending on how you map relationships between entities, you will
> rarely need to to call save, update or delete. NH will know what to
> do. I try to structure my applications so the only time I call Save is
> for transient root entities. and even those I try to limit. If you
> are working with a legacy database (ie. you cannot refactor the
> database) then you will have more calls to Save and Delete. possibly
> event Update.
Many of our objects are lazy loaded or proxied, but there does not
seem to be anything like an aggregate root nor distinctions between
entities and value objects. As I said in my post, our session.Load()
is scattered through the code (session-per-query, ugh) anywhere we've
encountered a LazyInitializationException. I have yet to research our
overarching session-management process if there is such a thing.
> one last thing to note with NH. all operations, both reads and writes
> require an transaction for NH to work properly. It's not that NH won't
> work without them, but you may see "funky" results without them. You
> can read up on 2nd level caching and POID generators for more
> information no why transactions are required (beyond ACID database
> operations).
>
> There are also a number of videos on the web about NH. Ayende has a
> great presentation at Skills Matter about NH.
I'll try to dig those up.
Thank you very much for the detailed response Jason, it helps immensely.
--Kaleb
> On Dec 16, 8:13 am, Oskar Berggren <oskar.bergg...@gmail.com> wrote:
>> 2010/12/16 Kaleb Pederson <kaleb.peder...@gmail.com>:
>>
>> > I'm working with a FAT-client application and need to figure out a
>> > better way to structure its DB usage, but I'm new to nhibernate and
>> > db-heavy applications. So, my first questions are about sessions:
>>
>> > 1) How heavy is a session? If every session must establish a
>> > connection to the database, then I'd expect there's going to be a fair
>> > amount of overhead and we're not going to want to create them very
>> > often.
>>
>> This is a matter of connection pooling. The connection can live longer
>> than the ISession. An ISession may even release the connection between
>> transactions.
>
> --
> You received this message because you are subscribed to the Google Groups "nhusers" group.
> To post to this group, send email to nhu...@googlegroups.com.
> To unsubscribe from this group, send email to nhusers+u...@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 nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
The solution proposed by Ayende
There is also my review to Effectus:
I agree with Fabio, there is a lot of material and i don't see much to invent. If this thread were about a new discovery, or a new pattern or something like that, the subject should be "An alternative to CpBT pattern" or "An alternative approach for handling a unit of work on fat clients applications"
--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
View specific DTOs are a very good idea and full in line with
command-query responsibility segregation (CQRS). Both Udi Dahan and
Greg Young have some good articles on the topic. It'll be a quite a
while before I can introduce anything like that as I have fundamentals
that need to be taken care of first.
> Get<> queries the database immediately. Load creates a proxy of the
> entity. Load will query the database once a mapped property of the
> entity is accessed. both take advantage of the Identity Map contained
> within the session. if the entity is already loaded then it will not
> query the database a second time.
Ok, so we're talking about proxying the entire object rather than
proxying for its properties which may be specified as lazy or proxy in
the mapping files? That could definitely be an optimization when the
data doesn't end up being necessary.
> Crtieria/Query also take advantage of the IdentityMap (IM), but they
> must query the database, then determine if the entity is already
> loaded in the map. if it doesn't exist int the IM, put the entity into
> IM. return the entities from IM.
Good to know.
> I use Load for queries that filter on an entity. for example
>
> var entity = session.Load<Entity>(id);
> var results = session
> .CreateQuery("from Other o where o.Entity = :e")
> .SetParameter("e", entity)
> .Future<Other>();
And I'd guess that nhibernate can optimize that so it's not making
multiple trips to the database? Or, as an example, that should be
better than the following:
var entity = session.Load<Entity>(id);
var results = session.CreateQuery("from other o where o.EntityPK = ?")
.SetInt32(0, entity.EntityPK)
.Future<Other>();
> "aggregate root nor distinctions between entities and value objects"
> These terms are probably overloaded/abused. by aggregate root I mean
> the root entity resolved from session. it's not a fixed object. For
> example. customer would be the aggregate root when managing shipping
> addresses, during order processing Order would be the aggregate root
> and customer may be a child of that aggregate.
Thanks for clarifying.
> finding a consistent NH session architecture is key to eliminate the
> headaches of session management. I'm primarily a web developer so my
> session management is easily solved with session per request. I've
> tinkered with thick clients. I would be inclined to push work to
> background threads and use a session per thread model for data access.
> in conjunction with pub/sub and view specific models I wouldn't need
> NH on the UI thread at all. a bit more complex than NH per form, and
> I've only tinkered with that model, but in theory it should be simple
> to maintain, once it's operational.
Yes, the architecture is very important. I hope to migrate toward
something like you've described. After I've read more I'm sure I'll
have a better idea what a sane and reasonable architecture will be for
our application.
Thanks for the great suggestions Jason.
--Kaleb