A few reasons to like NHibernate
Here is a very partial listing of features that I like in NHibernate.
- Change friendly - NHibernate make it very easy to handle changes, either in the mapping layer, or using 1:1 mapping to the database and asking NHibernate to create the database from the model or update the database schema to match the model. This means that making a change to the model is a very painless operation.
- Multi queries - the ability to batch several queries into a single database call makes for significant improvement in performance in almost any scenario.
http://ayende.com/Blog/archive/2007/05/20/NHibernate-Multi-Criteria.aspx
That was actually a marketing feature, initially, but it turn out to be really useful. - Future queries - building on the mutli queries capabilities, this allow you to retain a friendly synatx, but still get the perf benefits of multiply queries in a single remote call. Beside, you can now say that you are future proofing the application.
http://www.ayende.com/Blog/archive/2008/01/24/FutureltTNHibernateQuerygt.aspx - Batch updates - and I am still bitter about SqlCommandSet being internal. That is a major annoyance.
- Caching - NHibernate has 4 different caches, the identity map cache is common in OR/M, but NHibernate manages a second level cache as well. Which can be turned on by a config setting, which allows you to cache just about everything. NHibernate's caching is split to query caching (just the ids returned), entity cache (the data of the entities) and timestamp cache (which prevent stale data). All in all, they provide a very seemless experience, and make it incredibly easy to significantly improve the performance of the application without having to go and touch all the places where you call the DB.
In addition to that, NHibernate cache is pluggable, moving from the ASP.Net cache (including support for all the usual dependencies tracking) to distributed caching suitable for web farms scenarios.
This also enable other interesting scenarios, I know of at least one place that uses the cache as a fallback in case the database is down, for example. - Support for distributed scenarios - sharding, distributed caching, cache supported queries are few of the features that relates to that, just of the top of my head.
Googlinglive.coming your entities - Lucene integration - super fast search across your entities, including interesting options such as polymorphic searchs across the graph and safe query language that user are familar with (and no, full text searching at the DB level doesn't come close).- Flexible - I can extend just about every part of NHibernate that I want. Without changing NHibernate's code, that is, just by using the provided extension mechanism. From supporting wierd database types to adding AOP support to my entities. This means that I don't find the hood welded shut, which is all too often the case, when I need to do something slightly advance.
- Testable - NHibernate itself is easy testable, although I would still recommend going one layer above that for real testing, since it is generally too lower granularity to be useful in most cases.
- Non invasive - if I want to use NHibernate, I don't have to make any signifcant modifications to my code, my entities are POCO classes, without referencing NHibernate or being dependant on it. This is imprtant, because it means that NHibernate accepts the responsability to match my model, not the other way around.
- Complete abstraction - I have written full fledged enterprise applications, with high level f complexity, that had 0 (ZERO) SQL statements in them. I mean that as no queries in the code, no stored procedures, no DDL, nothing. NHibernate took over the entire thing, I didn't have to manage that at all. (Doesn't mean that I didn't test that, or that I wasn't profiling the application to see if it needed indexing or the like, but it was zero cost DB for most of the project).
- High performance options - see above for some of them, in general, NHibernate provides with a lot of options to increase performance. Here is a tidbit that I didn't mention so far, the various fetching straties that you can use (join, subselect, batched select, caching, multi queries, etc).
- Multi database support - you aren't limited to SQL Server, you can work on just about any database that you want. Even if you use SQL Server, the ability to run on a different database is very important, I routinely use this ability to enable me to run unit test on in memory databases, which are blazing fast. Without this, I would have to run tests against a database server, and the cost of the tests would be three orders of magnitude higher.
- Per query (and association) load options - this turn out to be useful in many cases, when I may need this flexiblity in the same unit of work.
- Enable non invasive cross cutting concerns handling. For example, if I want to handle INotifyPropertyChanged in my model, I don't have to add that to my model (thereby tainting it with what is for all intents and purposes UI concerns), I can add this capability directly through NHibernate:
http://www.ayende.com/Blog/archive/2007/04/17/Advance-Extending-NHibernate-Proxies.aspx -
Partial domain models - The ability to merge two diparate domain models into a single one dynamically is pretty powerful when you want to take a base model and use it from another one. This allows the ability to extend the model in some nice ways, such as building a separate library that handles a concerns without having to tie it to a particular domain implementation, or reusing a domain in different context.
Comments
Gee Oren, it looks like JBoss asked you to do some marketing for them ;) :P
Point 7 is interesting. With linq to Objects though I don't know if it's going to be used that much by the majority of developers. The point is that within a year or so, a lot of people will use linq and in-memory querying through linq to objects will be very common, so I'm not sure if this integration will appeal to a lot of people. That's not to say the subject at hand isn't interesting, after all, the 'majority''s opinion of what's cool is often related to pretty pictures and toolbox/ide oriented elements
Point 6 is a bit misleading though: 'distributed' also means WCF, remoting and the like, i.e.: sending a graph of objects over the wire, alter them there, get them back and persist them without hassle (i.e. without babysitting change tracking, attach/detach etc.)
First two links are broken,
Can you please provide some detail on in-memory database unit testing scenario (point 13)? What database do you use, whot is most convinient way to prepare its structure before test etc.
Hi Oren,
I agree. Just this week a I created a DAL for a legacy database by using NH. Up to this week n zillion different projects where writing hand crafted sql against this database. This hand crafted db access suffers from 1+N problems and intermingling of data access and business logic, like there is no tomorrow.
I discovered that the db hat a very good documentation of the tables and foreign key relationsships in html format. (at this point you might wonder if this db is part of a standard product: Yes.)
We used the very simple html parser from fit to parse the doc and created very plain mappings and classes with the help of stringtemplate.
All these mappings and classes are living an one assembly together with the Repositories. The problem with that: It is a anemic domain modell: The classes just have data, no behavior. But even then, no more had written sql. Simply use the SchemaExport to create a local instance of the db for testing and playing arround (Up to now you had to ask the admins for your own testinstance, which normaly was one per project).
Still having dumb classes is anoying. Going arround to all the posible users of the DAL and find out what behavior in those classes would help them would be a mayor effort. So I use NHibernate IInterceptor to not just create the classes we have already mapped. We have a way for clients of this DAL to register type replacements: Hibernate will not instantiate an object of type Account but the type MySpecialAccount, which is of course derived from Account, but defined in the client assembly. All of a sudden NHibernate returns not just data but exactly the functionality that the client wants to relate to this data. As there are multiple clients with different needs, every one of them can extend the anemic domain model.
Well, as this has just happened this week I am not sure if it will really be a success, but still to have these possibilities.
ralf
Wow. Nice list.
I would like to see how to do #1 ("asking NHibernate to create the database from the model or update the database schema to match the model") and #13. I think you were using SQLLite for that, right?
Nice post, but I'm probably just going to figure out how to deal with the limitations or just put up with the shortcomings in Linq to Entities (or even SQL).
Tuna, fixed, thanks for noticing.
Ralf,
Yes, exactly.
The ability to do this kind f stuff make it very easy to change things, without having concussion affect.
Frans,
The origin of this post is about as far from JBoss and marketing as you can imagine.
re: Lucene integration
If a developer think that they can replace what Lucene can do with in memory queries, they are welcome to try. I'll be at the competition, where it would not take an hour to run a query.
Lucene can index huge amount of data, and return results nearly instantly. This ability makes it very important when you want to build smart search screens.
re: Distribution
That is not my definition. But NH works just fine with that scenario.
I wouldn't recommend it because of the design implications, but it is possible to work this way.
Marcin,
The DB is SQLite, and the code to do that is part of Rhino Commons.
I think that I have a post or two about it, you can check the test cases for that.
Alberto,
1: SchemaExport and SchemaUpdate are your friends
13: Yes, SQLite in memory testing.
El,
Your loss, have fun.
Great post... I'm very excited to check out the Lucene integration. I was wondering if you are aware of any good sources of information related to extensible models in NHibernate? The use case I'm thinking of is to provide a core domain model that can be extended by a typical application plugin. For example, adding a one-many, many-many relationship from the base "contact", or adding new attributes on to the contact itself maybe. I've heard some of your complaints re: the big CRM apps and the awkward nature of using their API's, but if you know of any good articles on this sort of thing, I'd welcome the suggestions. Thanks!
Chris,
The reference implementation that I have is Rhino Security
@Ayende
On 7 is this NHibernate.Search, when reading this I tried to find out more about it but there doesn't seem to be a lot written about it.
The SQLite approach is interesting but how do people handle situation where the test relies on some pre-existing data (such as reference data like countries). I imagine you just need to run update scripts to ensure the DB is populated in advance of the test(s)?
Anyende, I created an app a couple of years ago that uses WCF for remoting and NHibernate for persistence. We send business entities across the wire, which took some finagling to make work. I think you have read about it here:
http://lunaverse.wordpress.com/2007/05/09/remoting-using-wcf-and-nhibernate/
It "works" but I would not repeat this architecture, mainly because it cedes the benefit of lazy loading. That's because if the client invokes a lazy proxy, boom, the session and proxies do not exist on the client. We have made some other provisions to avoid a performance nightmare, but performance is not so good. My question is, is do you know of some way to allow lazy loading in a WCF remoting scenario?
Is SchemaUpdate fully functional yet in NHibernate, or is the work to port it still under way?
@Colin The Hibernate Search documentation is applicable to NHibernate.Search
http://www.hibernate.org/hib_docs/search/reference/en/html_single/
I like NHibernate but the learning curve is huuuuge. I've seen quite a few very good developers that spent hours before being able to write any useful code. I think that there are a least a few reasons that prevent people from using it:
Documentation is far from being perfect
There are no tools that would support creation of mapping files. There are a few open source generators but they fail when applied to a complicated schema.
Handling of stored procedures is awkward (e.g. lack of return value, need to define primary key)
In other words the main drawback is the lack of tools.
@Kamran
Thanks, I'll take a look.
using nh and castle for over 2 years has changed both the way I develop and my attitude to development.
I do agree that the learning curve is great, especially for a mort. like me.
I learned both from doing a site with cuyahoga which coincidently is the cms this site uses. without using cuyahoga I would never have seen the true capabiluties.
from there I have discovered rhino and more.
one thing I would love to see in nh is lazy loading on properties. say I have a formula field. l don't want to run this every time.
Tim,
No, I don't have any suggestions, and I don't like this approach either.
Andres,
The port is complete, yes.
Test before you run this on production database.
Colin,
Check out the Fluent Fixtures idea from Aaron
Pawel,
If you want to learn a new tool, you need to understand it. No way around that. The documentation is fairly complete, and NHibernate in Action is very good.
About tools, there are out there, from VS designers to CodeSmith templates
Are there plans/thoughts on adding SQL Express support?
Sam,
SQL Express has been supported for the last 3 years or so (yes, before its conception)
Excellent! I was getting my info from the link below, which apparently isn't comprehensive or up-to-date.
http://www.hibernate.org/361.html
Thanks!
Sam,
There is not difference between SQL Express and any other edition of SQL Server.
Hi Oren,
Yes I agree there is alot to love about nhibernate and alot to look forward to aswell (2.0 bring it on). As developers we always want more though and without trying to dispel the present aura of love surrounding it, there are a few things I would love to see in future releases (if they aren't already planned that is).
For example I really liked mapping rewriting functionality you implemented in Rhino.Security, however this seemed trivial when using ActiveRecord if not only because you could subscribe to events using the ActiveRecordStarter to hook into the model creation. Similar events should be built directly into nhibernate to allow to us to catch SessionFactory creation and modify mapping at this point. I managed to implement this by injecting my own mapping rewrite functionality just before Cfg.BuildSessionFactory() which felt a bit disjointed. In addition I found documentation lacking when it came to the nHibernate Type system or using it programmatically to be specific. In the end it turned out to be fairly trivial to implement and with regards to documentation I can appreciate these scenarios are probably slightly rare and obscure.
That said I always feel a bit guilty requesting features or moaning about the lack of them as I could really just implement these myself and submit a patch...I would however prefer to have something like this implemented by a trusted and experienced nhibernate contributor such as yourself (hint, hint). :-)
Stuart,
The situation with NHibernate is different, you need those events with Active Record because AR hides the creation of the session factory.
With NHibernate you simply do:
cfg.AddAssembly(...);
// rewrite model here.
cfg.BuildSessionFactory();
Ayende,
Don't get me wrong. I know that I you need to spend some time to get familiar with a tool. Let me put it this way. It takes 10 times less time to be fully productive with Llblgen than with NHibernate. It's one of the reason why it's so hard to sell NHibernate. It's powerful but it's hard to grasp.
In terms of tooling none of the generators/templates (MyGeneration, CodeSmith) I've used did it job properly. There was always a problem with M:1 relations. I might be me but I think I would find quite a few people that share the same opinion.
Log4Net is easy to use and for sure much easier then Microsoft Logging block which is I suppose the main reason why it is all over the place.
@Ayende
Thanks and yeah I like it a lot.
We've never had to insert reference/static data (e.g. Countries) for testing as its all part of our database baseline so going for an approach like that would be a lot of work. If we ever need to do it then we'd know where to start though so ta.
Yeah, this is similar to what I did, however I injected my mapping rewrite code into an implementation of INHibernateInitializationAware component.
I think that after seeing how you hooked into the model creation in ActiveRecord it just seemed cleaner as the rewriting code is nicely abstracted.
But yes, looking at it again I suppose I could create this abstraction fairly easily myself...
Pawel,
I am sorry, but the situation that you describe conflicts with my experience.
It is very easy to start using NHibernate, and reaping the benefits occurs almost at once.
Yes, there is a lot of depth there, but you generally don't have to deal with it.
From my experience, most of the initial problems people have with NHibernate is not understanding the unit of work model, very bad DB schema or just standard bad practices.
Different people, different experience :)
I tried a few NHibernate code generation templates at the beginning and I agree they didn't work. To be fair though doing the mapping manually is relatively easy in most cases.
Ayende, great post! But I think you missed three points that are so easy take for granted when you're using NHibernate:
Ability to effortlessly add or remove properties to the results of select queries.
Adding a field to the schema and model is only a 3 step process (alter table, mapping file, and new {get; set;}) before it is immediately available to all existing code. Whereas it is a 5+n step process for other strategies (where n is the number of places the model entity is fetched).
Lazy-loaded properties - The ability to specify that certain large fields be loaded only upon specific request is a life-saver when you run into the unfortunate instance where large binary data is stored in the database.
Chris,
Actually, 18 is not supported :-)
Oren,
I thought NH supported lazy-loaded properties using proxies. It does support lazy-loaded 1-to-1 relationships, right? I guess this is different than a lazy-loaded property, but not by much. Maybe I misunderstood this capability.
It supports lazy loading of entities from other tables, not of the same table. (not quite true, but close enough)
The reason is that in most cases, it is much cheaper to load the entire row in one go, than loading them one by one.
The exception is when you have a BLOB in the table.
This is a problem from the programming perspective, because we would need to handle the ldfld stuff, and we can't do that without doing IL rewriting.
We can do that using property interception, but it would trip people who are used to access the field inside the class
Makes sense. Thanks for clarifying.
Having written data access layers before, I truly appreciate what NHibernate can do but I have one major complaint: Oracle support.
Last I checked, Oracle support did not include stored procs or CLOBs which are critical to our business model. If this has improved since the last time we investigated NHibernate at my company (I think it was Nov of 2007) then I'd love to use it.
Jeff,
No one on the team regularly test on Oracle, but some people from Oracle have contributed to NHibernate, so that is fairly surprising.
Can you create test cases for that?
good explanation, but it may be more helpful if for all items you provide links to more detail information.
for example, I know and use schema generation with hbm2ddl but info about updating base is new for me and there aren't enough documentation about it - so links to details can appreciably help.
I'm using NConstruct for NHibernate mapping files generation and it satisfies most of my needs. I'm working mostly with MS SQL and sometimes with Oracle databases. Having some problems with Oracle mappings but it seems some bugs are resolved now (didn't have chance to test yet).
Can somebody explain how do you decide between generating database from your object model or generating mapping files from database?
Kenny,
Unless you are dealing with a legacy database it would be in your interests to build your application top down or middle out.
This would mean designing your application with the focus on your objects/entities and services you require and that make sense within your domain, leaving the database to serve as a persistence mechanism for your object/domain model.
Using the database as the source of the design of your application will make your object model awkward and unnecessarily constrained.
That is my experience anyway...
@Tim Scott: there is a new project called NHibernate.Remote that supposedly handles lazy-loading remote NHibernate entities via WCF. I'm not saying this is a good thing, but it definitely piques my morbid curiosity...
http://slagd.com/?p=4
Do you know SQLObject (Python) or Gentle.NET? I used the latter, and what I liked about it is the ability to write the mapping data in the class, not in a different file, what avoids sync between them when you changed something.
What do you think about this? Can this be done with NHibernate?
Milton,
Take a look at Castle ActiveRecord
Probably not the best place to say this ;), but Diamond Binding has been pretty good at bringing nhibernate/active record based ORM to the masses where I work. I've found myself using it too for greenfields development.
Was there any luck with getting them to support castle builds out the box?
Comment preview