I'm creating a windows forms application with NHibernate. It's an MDI application, so there is no limit to how many forms the user can have open at the same time (probably many).
For most forms I want to have an "OK" and a "Cancel" button. Both close the form, but "OK" also saves the modified data to the DB. The forms can be pretty complex, and the modifications are likely to touch a whole graph of objects, adding some, deleting some, and changing some more. It would be good if the changes could be automatically detected and persisted as needed, without the need to manually keep track of each of them.
What would be a good way to do this?
<strong>Extra information</strong>: I can make whatever DB schema I want. I'm using MSSQL 2008 and currently have decided for GUID primary keys (with guid.comb generator) and a TIMESTAMP column for optimistic concurrency.
I tried to simply set
FlushMode of a NHibernate
Never, doing all modifications as needed, and then calling
Flush() if the user clicked OK. But that didn't work.
A few possible solutions, assuming that you're using one ISession per form instance:<ol> <li>Call ISession.Clear if the user cancels.</li> <li>Set the FlushMode to Commit and only initiate a transaction when the user clicks OK.</li> <li>Stick with your original approach of using Manual FlushMode. It should work and the behavior you're seeing is not a bug.</li> </ol>
Since you're using GUIDs for primary keys, you should not run into the issue of NH unexpectedly flushing a session because it needs the database to generate an identifier. You still need to be aware of scenarios where NH may flush before a select to ensure consistent results.
I don't think you need to worry about opening and closing the database connection. My understanding is that NH is very good about managing that.
This should help: NHibernate Best Practices with ASP.NET, 1.2nd Ed. (I know it's ASP.NET, but you should find the information useful and easily transferable to WinForms.)
In short, one should opt for a sesson per window architecture. Making impossible to open two different windows for the same exact task makes sense here. Then, you perhaps want to create an instance of the NHibernate ISession API on Form_Load(). At the end, if the user clicks OK, then just BeginTransaction(), Flush() the session, and Commit() the transaction, otherwise rolls it back.
Maybe if you wrap the whole thing in a transaction and commit the transaction when the user clicks OK?