views:

652

answers:

3

What are your experiences with the latest version of NHibernate (2.0.1 GA) regarding disconnected scenarios?

A disconnected scenario is where I fetch some object graph from NHibernate, disconnect from the session (and database connection), do some changes in the object graph (deleting in collections, adding entities, updating entities) and then reconnect and save....

+2  A: 

We tried this in a client-server architecture. Now we are moving to DTO (data transfer objects). This means, the detached entities are not directly sent to the client anymore, but specialized objects.

The main reason to move in this direction is not NHibernate, it is actually the serialization needed to send entities to the client. While you could use lazy-loading (and you will!) while you are attached to the session, you need to get all references from the database to serialize it.

We had lots of Guids instead of references and lots of properties which are mapped but not serialized ... and it became a pain. So it's much easier to copy the stuff you really want to serialize to its own structure.

Besides of that - working detached could work well.

  • Be careful with lazy loading, which will cause exceptions to be thrown when accessing non loaded objects on a detached instance.
  • Be careful with concurrency, the chance that entities had changed while they where detached is high.
  • Be careful if you need some sort of security or even if you want your server alown to make some data changes. The detached objects could potentially return in any state.
Stefan Steinegger
If you look at LLBLGenPro for example: before generating code, you can decide which template you will use. One will use the active record pattern called "self-servicing" and the other one will use the adapter (like the ADO.NET DataAdapter). The last one is handy when having a disconnected scenario (remoting or webservices).
Patrick Peters
@Patrick: I have to admit that I don't have a clue what you are talking about.
Stefan Steinegger
With the self servicing template LLBLGenPro will create a class (or more) where you can get and set properties (POCO-style) and then call a method like "Save". This object is self-servicing regarding state management and object-tree loading and SQL creation. The adapter style generates a light-weight class with only properties and is serializable; this object can be passed to an other object that is performing all the state management and SQL creation, etc...
Patrick Peters
Ok, but you don't need this when you have NH. So I don't know what you want to tell me with that. The serialization problem is independent from the database stuff. If you have a complex object graph, where the aggregate root references half of the database. Of course you can serialize half of the database, but usually you don't want to do it.
Stefan Steinegger
+4  A: 

You may take a look on session methods SaveOrUpdateCopy and Merge.

Here is an article which gives you more details: NHibernate feature: SaveOrUpdateCopy & Merge

The URL appears to have changed. It seems to now be http://www.codinginstinct.com/2009/11/nhibernate-feature-saveorupdatecopy.html
Richard J Foster
Thank you, I've fixed url.
A: 

The reference to Coding Instinct seems to cover how to update the database using disconnected objects okay. I have a slightly different problem with disconnected though. If I set lazy="false" and terminate the session, then put my object into a WinForms DataGridView then the DataGridView has a ghoulish tendancy to cause lazy load errors because it is looking into related objects that it best not look into. I would prefer a disconnected object to act like a POCO, not an nHibernate connected object.

Say I have a peice of code like this:-

        ISession session = nHib_SessionFactory.OpenSession();
        ITransaction tx = session.BeginTransaction();

        CustomerBO customer = session.Get<CustomerBO>(CustomerID);
        if (customer != null)
        {
            AddressBO defaultaddress = customer.DefaultAddress;
        }

        tx.Commit();
        session.Close();

The line that goes "AddressBO defaultaddress = customer.DefaultAddress;" is there to ensure that the DefaultAddress is available to the disconnected customer object. However, if I put the DefaultAddress into a GridDataView (inside an IList<>) then the GridDataView will cause a lazy load error (even though lazy load is false) because it wants to explore the DefaultAddress.Customers property which represents the one-to-many join in the opposite direction.

I can solve this by putting another line in like this:-

            IList<CustomerBO> defaultaddresscustomers = defaultaddress.Customers;

This means that that customer.DefaultAddress.Customers has results in it, even though I have no need for them. What this means is that for every object that I want to put into a DataGridView I have to return every object that is referenced by a property that that object contains, which could turn out to be a lot of data and a lot of waste, because I have no intention of using that data.

What is more, if someone on the client tinkers with these properties that I did not want to send to them and then I call session.SaveOrUpdateCopy I could end up with data being trashed that should never have been shown to the client. A bit of a security nightmare at the least.

Has anyone had any similar experiences, or have any better solution to this problem. Have they experienced this problem with any other data binding controls?

John Thompson