Is it possible to lazy load a related object during an open session but to still have the related object available after the session closes?
For example, we have a USER class and a related ROLE class. When we load a USER we also lazy load the related ROLE object. Can we have the USER and ROLE class fully loaded and available after the session is closed?
Is this functionality possible?
Short answer: no. You must initialize anything you will need after the session closes, before closing the session. The method to use to force loading a lazy proxy (without enumerating it) is NHibernateUtil.Initialize(USER.ROLES).
Long answer... kind of. It is possible to "reattach" objects to a new session, thereby allowing PersistentBags and other NH proxies to be initialized. The best method to use, given that you know the object exists in the DB but not in your new session, and that you haven't yet modified it, is Session.Lock(USER, LockMode.None). This will associate the object with the new session without telling NHibernate to do anything regarding reads or writes of the object.
HOWEVER, be advised that this is a code smell. If you are regularly reattaching objects to new sessions, it is a sign that you are not keeping sessions open long enough. There is no problem with opening one session per windows form, for instance, and keeping it open as long as the form is open, PROVIDED you close it when the window closes.
If you're dealing with a 1-1 relationship (0-1 role per user) then possibly the simplest option would be to configure it for eager fetching it rather than lazy loading. Lazy loading is really geared towards 1-* relatives, or objects that are particularly large and rarely needed. NH does a pretty fine job of optimizing queries to include eager data fast in scenarios like that.
Yes. Once the session is closed, any objects that were lazy-loaded will remain in memory and you can access them without any problems.
Related
I'm trying to make entity framework work properly with my application. The scenario I have is something like the following: Say I have 8000 items, and each item has 100 components. The way it currently works is I eager load the 8000 items and lazy load the components for each item, because eager loading the entire thing would be too slow on application startup.
As far as I understood in order to have lazy loading working, I need to keep the context alive for the whole application lifetime. So I have a single instance of the context that is open on startup and is closed on exit. I also use that to track changes and save changes.
However I've been reading about EF and many people advise against this approach, in favor of opening and closing contexts at each operation. My question is: how would you go about lazy loading properties, tracking changes, and saving changes if I cannot work with the same context?
Furthermore, I am already facing with issues since I use different threads to load data in the background or save in the background (say it's saving, if I edit a tracking property it raises an exception). I fixed some of them by using a FIFO queue (on a specific thread) for operations on the same context, however tracking properties won't respect the queue.
Some help would be greatly appreaciated as to how to use EF properly
This nhibernate setup suggests that it is better because I believe it doesn't start a transaction when the session is opened unless it is explicilty called i.e. lazy loaded.
I can't seem to grasp where in the code this lazy loading is taking place: http://nhforge.org/blogs/nhibernate/archive/2011/03/03/effective-nhibernate-session-management-for-web-apps.aspx
Can someone explain on this approach is better then opening a new transaction per web request?
the writer doesn't suggest that it's better because it doesn't start a transaction (it actually does- see the BeginSession function), but because it doesn't always start a session.
the 'lazy' refers to the intialization of the session.
Meaning- the session is only started when it's required.
(You're confusing it with lazy loading which has to do with loading values from the database, and is not relevant here).
The 'lazy' part is, as the writer explains, that the OpenSession function isn't called until it's needed (i.e someone is trying to use the Session object).
I'm trying to develop a web forms application using NHibernate and the Session Per Request model. All the examples I've seen have an HTTPModule that create a session and transaction at the beging of each request and then commits the transaction and closes the session at the end of the request. I've got this working but I have some concerns.
The main concern is that objects are automatically saved to the database when the web request is finished. I'm not particularly pleased with this and would much prefer some way to take a more active approach to deciding what is actually saved when the request is finished. Is this possible with the Session Per Request approach?
Ideally I'd like for the interaction with the database to go something like this:
Retreive object from the database or create a new one
Modify it in some way
Call a save method on the object which validates that it's indeed ready to be commited to the database
Object gets saved to the database
I'm able to accomplish this if I do not use the Sessions Per Request model and wrap the interactions in a using session / using transaction blocks. The problem I ran into in taking this approach is that after the object is loaded from the database the session is closed an I am not able to utilize lazy loading. Most of the time that's okay but there are a few objects which have lists of other objects that then cannot be modified because, as stated, the session has been closed. I know I could eagerly load those objects but they don't always get used and I feel that in doing so I'm failing at utilizing NHibernate.
Is there some way to use the Session Per Request (or any other model, it seems like that one is the most common) which will allow me to utilize lazy loading AND provide me with a way to manually decide when an object is saved back to the database? Any code, tutorials, or feedback is greatly appreciated.
Yes, this is possible and you should be able to find examples of it. This is how I do it:
Use session-per-request but do not start a transaction at the start of the request.
Set ISession.FlushMode to Commit.
Use individual transactions (occasionally multiple per session) as needed.
At the end of the session, throw an exception if there's an active uncommitted transaction. If the session is dirty, flush it and log a warning.
With this approach, the session is open during the request lifetime so lazy loading works, but the transaction scope is limited as you see fit. In my opinion, using a transaction-per-request is a bad practice. Transactions should be compact and surround the data access code.
Be aware that if you use database assigned identifiers (identity columns in SQL Server), NHibernate may perform inserts outside of your transaction boundaries. And lazy loads can of course occur outside of transactions (you should use transactions for reads also).
I have a system in winforms C#.Net 2.0 with ActiveRecord + NHibernate communicating with a PostgreSQL 9 database.
When user open the system, starts the communication with the DB by a new SessionScope(). For some users it works perfectly... but for others the system generates a memoryexception, identical to the problem of Marcio in msdn forum: link.
How can I solve this problem? The problem is in NHibernate! The error occurs when I try to close the ISession object or when I try to Commit the transaction.
An underlying reason for OutOfMemoryException can be outside of the code that you posted. You simply have a memory leak and it can be anywhere in your app. The exception will be thrown from the code that tries to allocate more memory, not necessarily from the code that causes memory leak. Use memory profiler to figure out what causes the memory leak.
It is very likely however that this issue is due to bloated 1st level cache in NHibernate. From SessionScope document:
At the same time, NHibernate is keeping tracks of changes to objects
within the scope. If there are too many objects and too many changes
to keep track, then performance will slowly downgrade. So a flushing
now and then will be required.
Get rid of GC calls, you don't need them.
Limit the scope of the session
Flush/Clear session periodically
Make sure that you use lazy loading appropriately (don't load information you don't need from database)
I see there are 2 possible scenarios as to the session handling:
Open one single ISession per request. Open it at request start and close it at request end.
Open one ISession per conceptual "unit of work". Many sessions are created for a request.
The approach #1 is the one I'm doing now. I'm a little bit worried about it because, although it works, it's a little bit difficult to debug. For instance, I have an object not being saved (even though I ordered it to) and I'm having trouble debugging since there's a LOT of things happening during a complete request life-cycle.
The approach #2 seems to be the standard best-practice (not sure about ASP.NET) and I'm sure it's pretty easier to debug. The problem I see is about inter-session communication. For instance: My Page class holds a reference to the User, which is a persistent object. Many of the operations receive the user as parameter. As the user belongs to a different session, I can't pass it as a parameter.
I'm biased to #2, but I don't know if it's the best practice, nor how to deal with cross-session object.
Thanks.
Most people do Session-Per-Request for the reasons you outline and for simplicity.
However, you can open and commit transactions for each "unit of work". So you will have many transactions for each session. (It is also usual practice to make sure that when the transaction is committed, the session is flushed at the same time).
For example, after clicking the save button, open and commit a transaction.
The session will take care of keeping track of all your entities. The transaction will take care of flushing to the database when necessary.
With this setup it should be easier to debug your problem.
For the ASP.NET project I'm working on now, I use a combination of these approaches.
I open an ISession at the beginning of a request and close it at the end of the request, as you do with your first approach, and I use the session to load any entities that need to remain attached to a session for the duration of the request.
However, when I need to save or update or delete an entity, I create a new transient object and hand it to a new ISession, separate from the one tied to the request. For additional units of work, I create additional sessions.
You may find NHibernate Burrow helpful, or at least interesting in this regard, as it is designed to assist with session management in ASP .NET applications, implementing the concept of a "long-running conversation" that spans multiple requests.
I think your real question is why cant I get my objects to save.
Even thought you are using a single ISession you still need to either Flush the session or commit transaction for some Save/Update/Delete actions to be commited.