I'm new to NHibernate (my 1st big project with it).
I had been using a simple method of data access by creating the ISession object within a using block to do my grab my Object or list of Objects, and in that way the session was destroyed after exiting the code block.
This doesn't work in a situation where lazy-loading is required, however.
For example, if I have a Customer object that has a property which is a collection of Orders, then when the lazy-load is attempted, I get a Hibernate exception.
Anyone using a different method?
Session management:
http://code.google.com/p/dot-net-reference-app/source/browse/trunk/src/Infrastructure/Impl/HybridSessionBuilder.cs
Session per request:
http://code.google.com/p/dot-net-reference-app/source/browse/trunk/src/Infrastructure/Impl/NHibernateSessionModule.cs
check out the SummerOfNHibernate webcasts for a great tutorial... What you're looking for specifically doesn't come until webisode 5 or 6.
Keep your session open for your entire unit of work. If your session is life is too small, you cannot benefit from the session level cache (which is significant). Any time you can prevent a roundtrip to the database is going to save a lot of time. You also cannot take advantage of lazy loading, which is crucial to understand.
If your session lifetime is too big, you can run into other issues.
If this is a web app, you'll probably do fine with the session-per-httpRequest pattern. Basically this is an HttpModule that opens the session at the beginning of the request and flushes/closes at the end. Be sure to store the session in HttpContext.Items NOT A STATIC VARIABLE. <--- leads to all kinds of problems that you don't want to deal with.
You might also look at RhinoCommons for a unit of work implementation.
Since you are developing a Web App (presumably with ASP.NET), check out NHibernate Best Practices with ASP.NET at CodeProject.
Related
I've got an mvc project. we have some data that must collected for each user. i created some singleton class to cache data for better responsibility.
somebodies avoided using singleton class in their projects.
i want to know do you prefer this and if not, what's your replacement??
The proper way in 99% is not reinventing the wheel. If you're not all right with System.Web.Caching.Cache, you can use System.Runtime.Caching.MemoryCache instance per user.
I don't see a reason why you should not cache data in your singleton. I'm also using this way of caching in order to greatly reduce the amount of database calls. Just make sure that you keep your cache up to date.
I don't know your project and its environment, but in my case it there were situations when the data in the DB gets changed from another application. I implemented a database trigger to resolve this issue. You should consider doing the same in your case, so whenever some of your locally cached data changes in the DB, you get notified and can update the cache.
I think I don't have to mention this, but caching of course usually only makes sense for relatively static data that does not change very often.
Recently I've been integrating NHibernate into our server application that exposes multiple services. The core service manages multiple instances of a class, and I understood that it is recommended to use the session-per-request pattern. So far so good.
One of the other services is a Site Settings service, which effectively manages a singleton: there is only a single instance of SiteSettings. I can follow the session-per-request pattern with this service as well, but it seems odd. Do I really need to create a new session for each request here? Why not create a single session for the service and keep using it? One of the advantages of the session-per-request pattern is that the session does not eventually cache all objects in the model. However, since I will only ever load a single instance in the session, I think this should not be a concern. Would I be better off using IStatelessSession rather than ISession?
Are there other reasons to use session-per-request here? One concern that comes to mind is what happens in case of a disconnection to the DB. Can I keep using the same session even after a DB error?
As an aside, I was thinking of storing each setting in its own column, which means I have to update the schema as settings are changed. I found this post: NHibernate Web Application - Managing User Preferences, where one of the comments is against using a table to store such configuration settings. I'm having a hard time coming up with alternatives (short of serializing the whole class and storing it as a blob). Are there different approaches?
Sessions aren't thread safe so I think you'd want more than one for your singleton
Can I keep using the same session even after a DB error?
No, presumably that would throw an exception and you're not supposed to reuse sessions after an exception. IMHO you should stick with the session per request pattern.
Are there different approaches?
Can you use a different row per config setting? So your User object would have a child collection of UserSetting objects. Each UserSetting would just be a key value pair.
I have NHibernate sessions cached in the ASP.NET session.
I came across a situation where a user edited an object so it's in their first level cache in the ISession. Another user then edited the same object.
At this point User1 still sees their original version of their edits where as User2 sees the correct state of the object?
What is the correct way to handle this without manually calling session.Refresh(myObj) explicitly for every single object all the time?
I also have a 2nd level cache enabled. For NHibernate Long Session should I just disable the first level cache entirely?
Edit: Adding some more terminology to what I'm looking to achieve from 10.4.1. Long session with automatic versioning the end of this section concludes with
As the ISession is also the (mandatory) first-level cache and contains all loaded objects, we can propably use this strategy only for a few request/response cycles. This is indeed recommended, as the ISession will soon also have stale data.
I'm not sure what kind of documentation this is for it to include both probably and then immediately say the session will have stale data (which is what I'm seeing). What's the solution to this right here or is there none?
You can't disable the first-level cache.
Check out "Optimistic concurrency control" in the NHibernate docs.
Also take a look at NHibernate.Burrow for long conversations.
Just use IStatelessSession instead of ISession.
Also keep in mind that NH wasn't designed to be used with long-living ISessions (as already mentioned by others). One problem is that you already mentioned. The other is that the performance drops significantly when there's a large object graph tracked by NH. Both problems could be avoided by using IStatelesSession.
It gives you detached objects not being tracked by NH.
Not sure about the reasoning behind keeping sessions in the ASP.NET session. Maybe you could provide some details?
Also remember that a session is a wrapper over IDbConnection. Keeping it open can easily lead to conneciton pool starvation.
Apparently this is a known shortcoming of NHibernate as detailed by documentation cited in my question.
Let's say you're building something simple, like a data entry/CRUD form for working on an entity called Customer. Maybe you pass the CustomerID in via Session state.
I tend to write a lot of fairly boilerplate plumbing code around handling that Session variable in a particular way. The goals vary slightly but tend to be things like:
Avoid cluttering the main flow of the page with plumbing code
Handle the back button intelligently
Remove the variable from Session and persist it to ViewState ASAP
Code defensively for failure situations where the state doesn't get passed, or is lost
Do you have a best practice for handling this situation? Do you have classes in your stack that handle this perfectly every time? Do you just call the Session variables directly? Do you use encrypted QueryString and avoid Session variables in this situation entirely in order to make the back button work a little better?
Lately I've been using Properties with Session variables. Here's a simple example that I just threw together, although please keep in mind that this example would not be very tolerant of the back button:
Private ReadOnly Property CustomerID() As Integer
Get
If Me.ViewState(Constants.CustomerID) Is Nothing Then
If Me.Session(Constants.CustomerID) Is Nothing Then
Throw New ApplicationException("CustomerID was not persisted.")
Else
Me.ViewState(Constants.CustomerID) = Me.Session(Constants.CustomerID)
Me.Session.Remove(Constants.CustomerID)
End If
End If
Return Me.ViewState(Constants.CustomerID)
End Get
End Property
So, how does your shop handle this? Thanks!
Teams I have worked on do not pass this kind of workflow information around in session, primarily because of the difficulty it poses to web farms/gardens. We think of session as a container for information that is relevant most (if not all) of the time from the moment the user first hits the site to the moment they leave. Even then, I'd only use session if that information was very expensive to retrieve/build, and only if I knew that the load balancer would stick the user to a particular server in a farm or that we had a suitable out-of-process session provider in place.
Instead I would pass this type of information via the query string, hidden input field, or ViewState (if enabled), and provide friendly error-handling when invalid values are sent. If history management is important, I would leverage ASP.NET AJAX history management.
I'm working on a ASP.Net webform app and I am wondering how long I should keep my data context around. Currently I create a context on each page load, and that context is used in every db access for the entire page load. Should I be using a context only in each method that needs it, and dispose at the end of the method? I understand that I can't access a object retrieved from the context once I exit that context's using block, but this isn't an issue with my design.
Steve Sanderson (author of Pro ASP.NET MVC Framework) has an interesting blog post on this issue. The gist of it is that the DataContext should be kept around per "unit of work", which basically correlates to a "request". I guess you could get away with shorter lifespans if you weren't modifying object and had no need to persist (update) any changes back to the DB.
You may also want to check out 'When should I dispose of a data context?' here on SO.
I'd say that you keep the context as long as you need it and it's appropriate. There's a balance to be drawn between life span of the context and the number of requests being made.
You don't want to create the context with every request to the database, similarly you probably don't want to maintain context for the entire life of the application (where that's possible).
I'd look at the effective transactions that the code is performing and look to have the context maintained within each of those. This granularity should also help with ensuring that your code is modular and extensible (as dependencies should be fewer).
I've done it the way you described as well as another way which is bound and destroyed based on the HTTP Request. That was allows a single page to use one DataContext from start to finish.
Overall, I haven't seen a big hit to performance doing it the way you're currently doing it.