Ayende @ Rahien

Hi!
My name is Ayende Rahien
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

@

Posts: 5,947 | Comments: 44,539

filter by tags archive

NHibernate – not all that glitters is gold


Manuel Abadia has some criticism on NHibernate that I wanted to respond to. First things first, though, it seems that I have been hasty in my response to a problem that Manuel reported, NH-1123. I really don't like it when other people do it to me, and I would like to apologize to Manuel for treating him in a manner I don't wish to be treated.

 As an aside, I have created a new bug on the JIRA, with a bit more focus on the underlying problem. This bug has now been fixed, and I would like to thank Manuel for (a) finding it, (b) persisting even after I wasn't as attentive as I should. Interesting bug, by the way.

He had several other things to say, which I want to respond to in details:

1) It is heavily tied to the java version (Hiberante), so a lot of the request and/or enhancements are ignored. If the java version is not going to add it, probably it will not be added to NHibernate.

 I wouldn't say that, NHibernate is focused on bringing us up to par with Hibernate, but that is certainly not saying that we aren't going to add things that Hibernate doesn't have. Right now, MultiQuery and MultiCriteria are stuff that Hibernate doesn't have and we do, and there are others.

At the same time, if a feature request is something that we can either develop from scratch or port from Hibernate, we would rather bring it from Hibernate. The main reasons are to make it easier to use documentation, built on already fixed bugs, maintain knowledge, and more.

2) Hibernate was started in 2001, and was designed to overcome a lot of the ORM problems. During these years, it has solved a lot of those problems, but other still remain and they can’t be fixed without heavily changing its design.

There are certainly things that I would change with NHibernate/Hibernate if I were able. One of the things on the very top of the list would be to turn the entire internals to AST manipulation and delay the actual generation of SQL to just before executing the query / command. We are working on that, actually. And you are more than welcome to join in and help us do so. And yes, I do mean you, personally, dear reader.

I would be interested to learn what the other problems are, by the way.

3) Even if it is extensible, the IInterceptor interface does not expose all the events that can be interesting to capture (For example, events after loading, updating or deleting data). The only way to handle that at the moment is to implement the ILifecycle interface by the entity itself, losing entity transparency.

Fabio Maulo has been doing tremendous amount of work on this very topic, and NHibernate 2.0 will have the full power of events and listeners from Hibernate 3.0. Most of the world have been completed, and can be found on NHibernate trunk, it opens quite a bit of possibilities.

4) No paging support in some nontrivial scenarios.

As I said, the bug was fixed, but even without that, I would still say that this is not correct. There are quite a few ways that you can do paging in NHibernate, the default approach is not always the best one.

5) There is no support for retrieving all the data at once for hierarchical queries

Here is one example of how to do just that :-)

Okay, that was cheating, since it used native SQL, but that did worked through NHibernate, and you got live entities back from it. No, NHibernate has not native support for doing hierarchical queries, and to support them we have the prerequisite of AST based internal, most probably. (At least the way I think about them)

There is also multi queries, which is what I use to do hierarchies all over the place, mainly because they are far cheaper than a single hierarchical query in real world scenarios (7 tables representing hierarchy, in my case).

To surmise, I would like to mention that NHibernate is an open source project. By its very nature, you are able to go into the code and fix things yourself! NHibernate's codebase is fairly big, but it is also well partitioned, so you are going to find it much easier to work with it than you would expect by simple size estimates.

If you have a problem, by all means, please report it, but do give a try at fixing it, that is going to be easier than you imagine.


Comments

Steve

If there was a way to group together the calls made in an object graph, it would help tremendously, it's still too chatty.

I have no idea how this can be improved, but it would help the negative perceptions of ORM's.

Ayende Rahien

Steve,

There are MANY ways to do this, actually.

What is the scenario?

Dario Quintana

Hi Ayende,

I thinks to treat with paging support (and other interesting stuff) for NHibernate, uNHAddIns it's a good approach, created for Fabio Maulo.

http://code.google.com/p/unhaddins/

Regards

Manuel Abadia

Ayende,

I replied to you here:

http://www.manuelabadia.com/blog/PermaLink,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx

Steve

Let me just make a simple one:

(Let's assume no lazy load here)

you have a Company with a list of Employees.

one to many

when I turn on nhibernate sql debugging I'll see like this:

select ... from Company where ... companyid = ?

select ... from Employees where companyid = ?

Two calls.

Let's say I wanted one call that was a join ?

Ayende Rahien

Steve,

You need to configure this at the mapping level:

IIRC, it is something like:

Mats Helander

"One of the things on the very top of the list would be to turn the entire internals to AST manipulation and delay the actual generation of SQL to just before executing the query / command."

I certainly agree with using an AST for all manipulation [* ahem * DOM over string manipulation, right ;-)] but why wait until the last moment before turning it into its final state, the sql string? Isn't it better to do that as soon as possible to allow the GC to collect all the objects from the AST?

/Mats

Ayende Rahien

The idea is that you want to delay that as late as possible to allow transformation of the AST at all levels.

Mats Helander

Ok, means we agree. Could I also suggest you generate a Sql Dom instead of strings from the AST? (Again, DOM over string).

/Mats

Ayende Rahien

Mats,

I don't think that I understand the different between AST and DOM

Mats Helander

I meant that first you parse the HQL, that will give you your AST (which is indeed a DOM). From there, you /could/ go right ahead and generate the resulting SQL strings directly. What I'm suggesting is that you don't do that, but instead (create the classes for and then) generate a SQL DOM from the AST. Then, finally, you generate the SQL strings from the SQL DOM - which can be done using visitors (where you can use different visitors for different databases). Makes sense? ´But perhaps NH is already doing this?

/Mats

Ayende Rahien

Okay, so you are talking about HQL AST and SQL DOM.

I don't really see the need to create two representations of the same thing. We could probably generate the SQL directly of the HQL AST.

Mats Helander

The AST is another representation of the "same thing" (the HQL string). Why do you see the need for that? /Mats

Ayende Rahien

I take a query (HQL, Criteira, Linq, etc) and generate an AST, process it through everything that we may need, and finally generate SQL from it.

That is the overall idea.

Frans Bouma

Mats: delaying the SQL generation till the final moment allows you to add/remove/manipulate elements in the query specification elements at various levels. I do that too. For example the eager loading/prefetch path stuff manipulates the query specification objects to optimize the node queries based on the data known at that moment. If the query would have been generated early on, it would have come down to SQL string manipulation which sucks :).

Another advantage is that you can centralize the tree optimizations for all databases and simply have 'sql generators' per database.

Steve: wanting a single query for 1:n related entities isn't always what you want: the PK side will get duplicated in the rows, and this can be potentially be a lot of times, which means that the amount of data returned is huge.

In Objectspaces they had a trick where they used a union query which unioned the query per node to the main set and had NULL values for the fields from the entities not fetched in that node, so if you wanted Customer + Order (1:n) you had 1 select with the customer fields and NULL values for the Order fields UNION 1 select with the order fields and NULL values for the customer fields. This would be still 1 resultset but not the data explosion of the duplicate rows.

Of course, having a multiple branched tree would give a lot of problems.

Mats Helander

Frans,

I absolutely agree about delaying the creation of the SQL until all the manuipulation has been done. All I'm saying is that the last possible time is probably going to be a bit before the SQL is actually used, and the earlier you can let the GC collect the AST, the better.

Ayende,

Yup, I understand, I'm just suggesting that your last step, "finally generate the SQL" be turned into a two-stepper: First generate an SQL DOM and then use visitors to spit out the SQL string from there.

One reason for this is that it allows you to isolate many of the db differences to this last step, using different visitors to support different databases and allowing you to move complexity out of the AST-SQL transformation phase.

Take joins for example. Your SQL DOM would only have one format for joins, meaning that the AST-SQL transformation would only have to work with one join format. Then the different visitors turn the SQL DOM joins into the correct join syntax for their respective databases.

I just think that a year from now, you may be posting "There are certainly things that I would change with NHibernate/Hibernate if I were able. One of the things on the very top of the list would be to turn the entire internals to ****SQL DOM manipulation and delay the actual generation of SQL to just before executing the query / command."

/Mats

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB Sharding (2):
    21 May 2015 - Adding a new shard to an existing cluster, the easy way
  2. The RavenDB Comic Strip (2):
    20 May 2015 - Part II – a team in trouble!
  3. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  4. Interview question (2):
    30 Mar 2015 - fix the index
  5. Excerpts from the RavenDB Performance team report (20):
    20 Feb 2015 - Optimizing Compare – The circle of life (a post-mortem)
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats