How to keep long running NHibernate Session data consistent? - c#

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.

Related

I Need to cache data on my mvc project. what's proper way?

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.

Entity Framework POCO long-term change tracking

I'm using .NET entity framework 4.1 with code-first approach to effectively solve the following problem, here simplified.
There's a database table with tens of thousands of entries.
Several users of my program need to be able to
View the (entire) table in a GridRow, which implied that the entire Table has to be downloaded.
Modify values of any random row, changes are frequent but need not be persisted immediately. It's expected that different users will modify different rows, but this is not always true. Some loss of changes is permitted, as users will most likely update same rows to same values.
On occasion add new rows.
Sounds simple enough. My initial approach was to use a long-running DbContext instance. This one DbContext was supposed to track changes to the entities, so that when SaveChanges() is called, most of the legwork is done automatically. However many have pointed out that this is not an optimal solution in the long run, notably here. I'm still not sure if I understand the reasons, and I don't see what a unit-of-work is in my scenario either. The user chooses herself when to persist changes, and let's say that client always wins for simplicity. It's also important to note that objects that have not been touched don't overwrite any data in the database.
Another approach would be to track changes manually or use objects that track changes for me, however I'm not too familiar with such techniques, and I would welcome a nudge in the right direction.
What's the correct way to solve this problem?
I understand that this question is a bit wishy-washy, but think of it as more fundamental. I lack fundamental understanding about how to solve this class of problems. It seems to me that long living DbContext is the right way, but knowledgeable people tell me otherwise, which leads me to confusion and imprecise questions.
EDIT1
Another point of confusion is the existance of Local property on the DbSet<> object. It invites me to use a long running context, as another user has posted here.
Problem with long running context is that it doesn't refresh data - I more discussed problems here. So if your user opens the list and modify data half an hour she doesn't know about changes. But in case of WPF if your business action is:
Open the list
Do as many actions as you want
Trigger saving changes
Then this whole is unit of work and you can use single context instance for that. If you have scenario where last edit wins you should not have problems with this until somebody else deletes record which current user edits. Additionally after saving or cancelling changes you should dispose current context and load data again - this will ensure that you really have fresh data for next unit of work.
Context offers some features to refresh data but it only refreshes data previously loaded (without relations) so for example new unsaved records will be still included.
Perhaps you can also read about MS Sync framework and local data cache.
Sounds to me like your users could have a copy (cached) of the data for an indefinate period of time. The longer the users are using cached data the greater the odds that they could become disconnected from the database connection in DbContext. My guess is EF doesn't handle this well and you probably want to deal with that. (e.g. occaisionally connected architecture). I would expect implementing that may solve many of your issues.

Managing sessions for a singleton entity with NHibernate

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.

How long should I keep my LINQ DataContext around? ASP.Net page

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.

Best way to manage session in NHibernate?

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.

Categories