How should I have the NHibernate Session Factory and the sessions for a WinForms application?
Should the SessionFactory be a singleton? Or can I create it every time? What about sessions and transactions?
Any help would be appreciated. Thanks
The session factory should be a singleton since it is expensive to create. It is thread safe so there is no threading issue with using it.
I have used the session-per-conversation pattern in winforms applications, and have found it to work well. With this pattern you use the same session for a series of operations that belong together. As I see it, a conversation in a winforms app could, roughly, be mapped to a GUI operation in your application.
Using a new session for every GUI operation helps keep the session small enough to to avoid performance problems with to many entities in the first level cache, while at the same time avoiding using a separate session for every operation, which also can cause performance problems.
To implement this you then create a new session before handling the GUI command, and when the command has been handled you dispose the session. Below is an example of this, which uses a class (PersistenceContext) that creates a session when it is instantiated and disposes the session when it is disposed. This class can then create repositories that use the current session.
public void SomeGuiEvent(...)
{
using (var context = new PersistenceContext())
{
ProcessStuff(context);
}
}
There are ofcourse many other options of how to implement this, but however you choose to implement it, I can recommend the Session-per-conversation pattern when using NHibernate in a Winforms app.
Here is an msdn article showing sample application built by Oren Eini (Ayende Rahien): Building a Desktop To-Do Application with NHibernate
This has been asked a few times on Stack Overflow.
The Session Factory should be a singleton, because they are expensive to create.
For Sessions, there seems to be a rough consensus on a "one session per form" approach for NHibernate and WinForms. This means you should open a session when you open a form that accesses your database, and close the session when you close the form.
Look at the answers to this question -
What should be the lifetime of an NHibernate session? - for some more detailed descriptions, and some good links for further reading.
Related
Apologies if this is a dumb fool question, but I'm tired today and google isn't helping. This must be a common problem, but nothing I've found answers the question.
Whenever I've made use of Entity Framework in clickonce desktop applications, I've suffered a bit with the "entity object cannot be referenced by multiple instances of IEntityChangeTracker" error. This arises when multiple versions of the same database object are updated by different versions of the context.
On a web project, it's easy to bypass this issue by sending all the Db calls through some sort of singleton pattern on the server. If you're farming out a lot of Db update/insert calls to a service, you can do the same.
But what if you had a distributed application (e.g. WPF via clickonce) which potentially had a lot of users connecting to the database. Each user has their own install of the code, so even if you separate out the business logic from the Db logic, each user will still have their own copy of the context.
Is there any sort of pattern or technique that would allow inserts/updates direct from the application while avoiding the "multiple contexts" problem? Or is using something like a Windows service the only way to achieve this?
Can you reproduce this error even with a single user running your app?
Because getting "entity object cannot be referenced by multiple instances of IEntityChangeTracker" error means that you are creating 2 DBContext in your code and trying to manage a entity (created or readed) from a context through the other context. Nothing about distributed concurrency. Nothing about multiple users.
Check this SO question and try to identfy the error pattern in your code. In the example the two context are in memory but, as every entity keeps a reference to its IEntityChangeTrackeer, you can get this error even if its DbContext was disposed and you try to manage the entity with other context.
As a very rudimentary scenario, let's take these two operations:
UserManager.UpdateFirstName(int userId, string firstName)
{
User user = userRepository.GetById(userId);
user.FirstName = firstName;
userRepository.SaveChanges();
}
InventoryManager.InsertOrder(Order newOrder)
{
orderRepository.Add(newOrder);
orderRepository.SaveChanges();
}
I have only used EF in web projects and relied heavily on the stateless nature of the web. With every request I would get a fresh copy of the context injected into my business layer facade objects (services, managers, whatever you want to call them), all of the business managers sharing the same instance of the EF context. Currently I am working on a WPF project and I'm injecting the business managers and subsequently the repositories that they use directly into the View Model.
Let's assume a user is on a complicated screen and his first button click calls the UpdateFirstName() method. Let's assume SaveChanges() fails for whatever reason. Their second button click will invoke the InsertOrder() method.
On the web this is not an issue as the context for operation #2 is not related (new http request) to the context used by operation #1. On the desktop however, it's the same context across both actions. The issue arises in the fact that the user's first name has been modified and as such is tracked by the context. Even though the original SaveChanges() didn't take (say the db was not available at that time), the second operation calling SaveChanges() will not only insert the new order, it will also update the users first name. In just about every cause this is not desirable, as the user has long forgotten about their first action which failed anyway.
This is obviously being a silly example, but I always tend to bump into these sort of scenarios where I wish I could just start fresh with a new context for every user action as opposed having a longer lived (for the life of the WPF window for example) context.
How do you guys handle these situations?
A very real interrogqation when coming from ad hoc desktop apps that hit the database directly.
The answer that seems to go with the philosophy for ORMs is to have a context that has the same lifespan as your screen's.
The data context is a Unit Of Work implementation, in essence. For a web app, it is obviously the request and it works well.
For a desktop app, you could have a context tied to the screen, or possibly tied to the edit operation (between loading and pressing "save"). Read only operations could have a throwaway context (using IDs to reload the object when necessary, for example when pressing a "delete button" in a grid).
Forget about a context that spans the entire application's life if you want to stay aware of modifications from other users (relationship collections are cached when first loaded).
Also forget about directly sharing EF entities between different windows, because that effectively makes it an app-wide and thus long lived context.
It seems to me ORMs tend to enforce a web-like design on desktop apps because of this. No real way around this I'm afraid.
Not that it is necessary a bad thing in itself. You should normally not be attacking the database at the desktop level if it is to be shared between multiple instances. In which case you would be using a service layer, EF would be in its element and your problem would be shifted to the "service context"...
We have a large WPF application that calls WCF services to perform CRUD operations like ‘UpdateFirstName()’ or ‘InsertOrder()’. Every call into the service creates a new ObjectContext, therefore we don’t need to worry about inconsistent ObjectContexts hanging around.
Throw away the ObjectContext as soon as you are done with it. Nothing’s wrong with generating a new ObjectContext on the fly. There’s unnoticeable overhead in creating a new ObjectContext and you’ll save yourself many future bugs and headaches.
Suppose you do create a new ObjectContext each time a method is called on your repository, the below snippet would still give you transaction support by using the TransactionScope class. For example,
using (TransactionScope scope = new TransactionScope())
{
UserManager.UpdateFirstName(userid,firstName);
InventoryManager.InsertOrder(newOrder);
scope.Complete();
}
One completely different way is writing all changes to the database directly (with short lived database contexts). And then add some kind of draft/versioning on top of that. That way you can still offer ok/undo/cancel functionality.
Sorry for yet another question about EF4 context lifespan, but I've been wondering about this for a while and I do not seem to find the answer. I'm not very familiar with lots of patterns or overcomplicated stuff (in my point of view) so I want to keep it simple.
I work with an ASP.NET application where the context is managed by each http request which is a very good approach in my opinion.
However I'm now working with a winforms application and I sometimes have transactions or reports that will not perform very well if I simply create the context for each query. Not that this performance issue is a very problematic thing, I just want to hear if there's a simple strategy as per HTTP request in ASP.NET for winforms?
Don't create a context for each query. At the same time, don't create a context that gets used for the entire lifetime of a Form (or your application).
Create a context for a single Unit of Work (which can encompass many queries).
That way you have all of your changes encapsulated in the context and you let Entity Framework wrap the database calls in a pretty little transaction without having to worry about it yourself.
I prefer to abstract the Repository and Unit of Work patterns out of the Entity Context so that I can use them independently (which makes everything very clear). MSDN actually has a decent article on the details:
MSDN - Using Repository and Unit of Work patterns with Entity Framework 4
I am in the middle of development of a WPF application that is using Entity Framework (.NET 3.5). It accesses the entities in several places throughout. I am worried about consistency throughout the application in regard to the entities. Should I be instancing separate contexts in my different views, or should I (and is a a good way to do this) instance a single context that can be accessed globally?
For instance, my entity model has three sections, Shipments (with child packages and further child contents), Companies/Contacts (with child addresses and telephones), and disk specs. The Shipments and EditShipment views access the DiskSpecs, and the OptionsView manages the DiskSpecs (Create, Edit, Delete). If I edit a DiskSpec, I have to have something in the ShipmentsView to retrieve the latest specs if I have separate contexts right?
If it is safe to have one overall context from which the rest of the app retrieves it's objects, then I imagine that is the way to go. If so, where would that instance be put? I am using VB.NET, but I can translate from C# pretty good. Any help would be appreciated.
I just don't want one of those applications where the user has to hit reload a dozen times in different parts of the app to get the new data.
Update:
OK so I have changed my app as follows:
All contexts are created in Using Blocks to dispose of them after they are no longer needed.
When loaded, all entities are detatched from context before it is disposed.
A new property in the MainViewModel (ContextUpdated) raises an event that all of the other ViewModels subscribe to which runs that ViewModels RefreshEntities method.
After implementing this, I started getting errors saying that an entity can only be referenced by one ChangeTracker at a time. Since I could not figure out which context was still referencing the entity (shouldn't be any context right?) I cast the object as IEntityWithChangeTracker, and set SetChangeTracker to nothing (Null).
This has let to the current problem:
When I Null the changeTracker on the Entity, and then attach it to a context, it loses it's changed state and does not get updated to the database. However if I do not null the change tracker, I can't attach. I have my own change tracking code, so that is not a problem.
My new question is, how are you supposed to do this. A good example Entity query and entity save code snipped would go a long way, cause I am beating my head in trying to get what I once thought was a simple transaction to work.
A global static context is rarely the right answer. Consider what happens if the database is reset during the execution of this application - your SQL connection is gone and all subsequent requests using the static context will fail.
Recommend you find a way to have a much shorter lifetime for your entity context - open it, do some work, dispose of it, ...
As far as putting your different objects in the same EDMX, that's almost certainly the right answer if they have any relationships between objects you'll want them in the same EDMX.
As for reloading - the user should never have to do this. Behind the scenes you can open a new context, reloading the current version of the object from the database, applying the changes they made in the UI annd then saving it back.
You might want to look at detached entities also, and beware of optimistic concurrency exceptions when you try to save changes and someone else has changed the same object in the database.
Good question, Cory. Thumb up from me.
Entity Framework gives you a free choice - you can either instanciate multiple contexts or have just one, static. It will work well in both cases and yes, both solutions are safe. The only valuable advice I can give you is: experiment with both, measure performance, delays etc and choose best one for you. It's fun, believe me :)
If this is going to be a really massive application with tons of concurrent connections I would advise using one static context or one static, core context and just few additional ones just to support the main one. But, as I wrote just few lines above - it's up to your requirements which solution is better for you.
I especially liked this part of your question:
I just don't want one of those
applications where the user has to hit
reload a dozen times in different
parts of the app to get the new data.
WPF is a really, really powerful tool and basically times when users have to press buttons to refresh data are gone forever. WPF gives you a really wide range of asynchronous, multithreading tools such as Dispatcher class or Background worker to gently refresh desired data in the background. This is really great, because not only you don't have to worry about pressing various buttons, but also background threads don't block UI, so data is refreshed transparently from user's point of view.
WPF together with Entity Framework are really worth the effort of learning - please feel free to ask if you have any further concerns.
I have used NHibernate in web applications before. I must admit that I am still learning NHibernate and do not totally grasp the art of session management. So I would like to use NHibernate within a Win Forms application that I am writing. I hear that session management in a Forms application is a bit different. Sessions must be opened and closed on a conversation basis. Yes? Does anyone know of a good example of this? Or perhaps some cohesive documentation explaining session creation and tear down within a win32 app?
Thanks,
Nick
There is already a pattern established for managing NHibernate sessions in WinForms applications called Conversation per business transaction. A good description can be found here:
http://fabiomaulo.blogspot.com/2008/12/conversation-per-business-transaction.html
http://fabiomaulo.blogspot.com/2009/01/using-conversation-per-business.html
Basically it uses a conversation abstraction: it can start, pause, resume, end. Each operation does automatic session and transaction management. I highly recommend it, definitely worth taking a look.
Here are some good pointers on this subject.
uNHAddins has support for session-per-business-transaction. We are using it on a WinForms app.
http://gustavoringel.blogspot.com/2009/02/unhaddins-persistence-conversation-part.html