After ten months of public CpBT I still seeing people fighting to find a pattern to manage the NHibernate session in WinForm/WPF.
I’m not sure but perhaps one reason is ours uncoupled examples. So far, in the examples available in uNhAddIns, we have used IoC/DI and AOP, MVP/MVVM/MVC, DAO/Repository trying to show a more real and uncoupled example of a possible application. In this post I have tried to show that Dependency Injection is not the devil implementing a “10 minutes container” (here the code of the container and here the code of its configuration).
This time I’ll try to make a WinForm application, more coupled as possible… perhaps is more easy to uncouple a coupled application than couple an uncoupled.
Targets / Warning
The main target is allow to beginners an easy usage of debugger to follow the execution. I’ll try to avoid any kind of external framework other than NHibernate, NHibernate.Validator and WinForm, avoid any kind of architectural abstraction and so on. In practice the result should be a monolithic WinForms application with object binding.
I know that the final result is not a good example about “how create an WinForm application with NHibernate” but perhaps it will be useful to new users coming from VB6 and/or DataBinding applications.
Preparing the environment
After download the example (see below) what you need is only VisualStudio2008 and MsSQL-EXPRESS. The zip contains NHibernate 2.1.0GA and its dependencies and the last available NHibernate.Validator 1.2.0.
Before run the application you need to create an empty DataBase is your MsSQL-EXPRESS named “Chinook”. You can create it using SQL Server Management Studio Express or using command line:
C:\>sqlcmd -S YourMachine\SQLEXPRESS
1> create database Chinook
If you want change the DB name remember that you will need to change the connection string in the App.config file:
Server=(local)\SQLEXPRESS;initial catalog=Chinook;Integrated Security=SSPI
Quick Show: NHibernate’s session, the Unit of Work
During the first show have a look in the bottom side to see when the hit to DB happens.
The first is a simple input form with object binding an error info; as you saw pressing “OK” two queries are executed: the first to retrieve the high value of HighLow for the Artist entity and the second to insert the new Artist.
In the second part I’m showing two instances of the same form. In instance on the right side, pressing “Add” I’m creating a new instance of the form used for the first part but this time pressing the button “Ok” nothing happen with the DB because the “Jethro Tull” artist is part of a different UnitOfWork (the “Artist Form” is sharing the same NHibernate’s session with “Artists Form” in the right). When I click “Refresh” on the left form the application go to DB to retrieve the refreshed list but nothing change because the UnitOfWork in the right was not committed. When I try to click “Refresh” on the right form a message is showed because there are pending operations in the UoW (the NHibernate’s session is dirty). Finally I’m committing the work of the right form and you can see the hit to DB to insert “Jethro Tull”; at this point the refresh of the left form will find the new Artist instance.
Full Object binding and IDataErrorInfo support
In this show you will see entities implementing INotifyPropertyChanged/IDataErrorInfo and child collection supporting BindingList<T>.
The relationship between Album and Tracks is a classic Master-Details and, as you can see, all is working as data-binding.
If you need some explication about the code, please strictly related to NHibernate usage, you can leave a comment here or you can use the nh-users group.
Another download place is here.
P.S. test everything using only F5 was not so fun for me.
Great work guys!ReplyDelete
Just in time Fabio!ReplyDelete
I have to start a new winform project with Nh and this is not really my normal enviroment ;)
Many, many tnx!
ps(OT): how about this book for databinding in winform? http://tinyurl.com/nm2s57
Great and really wellcome article. It helps a lot understanding a good practice for ISession usage/management in a wiwform app, which was "hidden" by your CpBT. In this way someone that wants to implement his own way of abstracting the usage of DAL can understand (faster) what to do with the session.ReplyDelete
I'll have one maybe trivial question strictly related to your example, just for the sake of better understanding:
- You configure session.FlushMode = FlushMode.Never;
- Then you Session.Save() every new created object, so basically you make your session aware of all objects of the "conversation"
- In the end you either flush or dispose the session.
Seems the right and simplest way.
Is there any advantage or performance reason to do that over an use scenario like this:
- session.FlushMode = FlushMode.AfterTransaction;
- do work (create or update enities) but do nothing with the session.
- in the end either dispose the session or loop through all entities and SaveOrUpdate() them and Commit() (Iknow this looks ugly, but again it is just for the sake of understandding).
I know that in my scenao you don't have theadvantage of using ISession.IsDirty, bt other that that is there anything else?
When you are loading entities, through NH, NH will maintain your entities in the session and if the session is open you can work with lazy-loading.ReplyDelete
You can choose various ways to work with the session in winForm/WPF but that was the problem before CpBT:many ways but all with many problems.
If you have a look to ChinoOk-Mediamanager examples (by José Romaniello) using CpBT, you will have the "problem" to find where is NH and not "how manage NH session".
Thanks Fabio, I'm already in the process of reading Jose's work and I'll take a deeper look at your CpBT architecture.ReplyDelete
"using CpBT, you will have the "problem" to find where is NH" :), Yes I know, that was my problem.
I know about lazy loading, I was only refering to a slightly usage of session, pointly to the moment of calling Session.Save() on newly created objects and a different usage of FlushMode (AfterTransaction).
Err.. to be more clear, my legacy app uses identity generators :( so a Save() on a new object will be more usefull when really wanting to save an entity in DB.
Great example! Simple, but for beginners perfekt.ReplyDelete
Give me more of this! Pure Winforms with databinding and validation without any external application frameworks and services. But there is a bug. And I do not know how I can fix this. Problem: Pressing first time a key, while insert a new Album, the first Character is deleted?! How can i fixed this? You can see it in your video too.
I know this is an old post but the link seems to be broken. Any chance of reposting the example?ReplyDelete
click on the zip-folder image.
I've tried your example, however it has the same BindingProblem as my code has. If you have a look at the video here: https://dl.dropbox.com/u/8624357/ChinookWinForms_NHibernate_Example.avi
you'll notice, that the binding fails, if the track list is empty. It does add a new Track object, but it neither binds the object (it's all empty when reloading the album) nor does it validate it's properties properly. As soon as there's one track in the track list, adding more tracks works as a charme.
Some minor issue (also shown in your video) - when adding a new album, the first letter is swallowed.
do you have an explanation for the binding issue with the empty track list?
the download link is not work,where i can get the project source?ReplyDelete