Random NHibernate gotchas

Skrevet - Sunday, September 6th, 2009 kl. 21:13 | Kategori - * Coding, English posts

Nhibernate is extremely flexible and powerfull. Some details will have you tearing your hair out in frustration, though – at least untill you get that… ‘Ahaaah’ experience. Below, I’ll try to give you a few of the ones, that had me scratching my head:

The whole collection-issue that I mentioned in my last post can be frustrating if you missed the point with NHibernate using reference equality. In most situations you will not notice that one untill it is too late as it will be non-noticable in small datasets (if you are not paying attention to the SQL output, of course).

Another thing about equality – often, you will have entities publish an ID-field mapped to an Identity-column in the DB (for look-up purposes) and have it backed by a field. If you decide to use the ID for equality-purposes and have the property mapped with access: field be aware that any proxy from that persistent class will have different values for the field versus the property – the field will always be 0! So, always use the property in Equals(). Also, when considering equality in general, be sure not to use any lazy-loading entities as they will be loaded whenever equality has to be determined (WPF does a lot of that!). A rule of thumb is to use all properties for a value-type class (as per the DDD-terms) and only the ID for persistent aggregates (especially when they will be used as attached aggregates). The reason for this is that lazy-loaded entities do not have to be

evaluated (ie. loaded) to determine equality. I used to be a DBA in former employments and have spent a lot of time normalizing tables and I grew accustomed to mapping each fine-grained object to it’s own table – this is performance-killing! Consider the traditional simple Customer-class consisting of an accountnumber, a physical address, a billing address and billing information. If you map this to three-four tables (one for the customer, one or two for the addresses, one for the billing information) – NHibernate will unleash a LEFT OUTER JOIN hell of magnitudes (or a series of SELECT’s that will have your DB spinning out of control if you have yet to mark it to use sub-selects or outer joins)… Now consider when you start using the customer in other objects… The lesson here is that your typical one-to-one relationships with objects that will most likely not be null should be mapped as components and thus for the DB’s sake exist in the same table. Only consider a seperate table, if the associated class will often be null, or rarely used (lazy-load).

Inheritance and generics is another issue – just because NHibernate supports both, doesn’t mean you have to use it! It is most often not a perfect match and you will be twisting NHibernate into a knot to conform to your domain or vice versa. Also, remember that if you have an associated aggregate that is mapped with the base class – the resulting lazy-loaded proxy will always be the same type as the base class – never one of the derivatives. (See Ayende’s blog for further details as to why). Use it sparringly and be aware that mapping files do not support open generics – so, if your inheritance tree consists of a generic superclass – you cannot use it as the base class in the mapping unless it is a closed generics (and then it is a really advanced case – and you should really try for a simpler solution…). Generally speaking – using generics and inheritance in your mapping files will most often lead you into a world of hurt when the dependencies evolve and a key class in the inheritance chain will suddenly no longer conform to the dependencies. It is bad enough to have that happen to your domain – if you add data-migration head-aches to that mix… you’ll end up being wary of making needed changes to your domain.

All this said – if you stay clear of the pitfalls, NHibernate is a very nice fit for most agile TDD/BDD/DDD projects with databases as the early iterations will benefit from the easy DB-schema generation and the reduced DB-work. Later on, you’ll have to somehow solve the data-migration issues for projects in production – most customers will not take it lightly when you drop their databases for the new version to take effect… I have yet to find a silver-bullet there (there are products out there, but I have yet to need one badly enough to actually test them). My experience is that Active Record (which uses NHibernate under the covers) is really good for the early iterations – and then shift to full-blown NHibernate when you start running into the advanced stuff. DBA’s may seem like they get the short end of the stick and be out of a job, but it is actually a win-win situation – they get to do the fun performance-tuning part of their job in favour of the error-prone database generation part.

Feed | Trackback |

Post a Comment