Friday 12 February 2010

Quey across a join in nHibernate

My god, I don't think I've ever come across any framework with quite such a poor popularity-to-documentation framework as Fluent nHibernate. Everyone is using it, but no one writes down how.

Stupid nHibernate.

So, after spending ages trying to get something as simple as a rowcount, today I have spent an equally frustrating period trying to get a results set which does a logic OR operation across a joined table. Something as petty as this, in SQL terms:


SELECT * from product p
inner join sku s on s.id = p.id
WHERE p.Name like '%widget%'
OR s.SkuCode like '%wd_%'


The issue arises because even though my mappings are correct, nHibernate throws a wobbler at you if you start with Product and try and get it to recognise that it should be able to filter on a field in the joined sku table. This, for example, compiles but fails horribly even though to my mind it's the intuitive way of presenting the above query in nHibernate:


Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.Add(Expression.Or( _
Expression.Like("Name", "widget"), _
Expression.Like("SkuCode", "wd_"))) _
.List()


No, what you have to do is set up a CreateAlias to the table and use that:

Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.CreateAlias("Skus", "sku") _
.Add(Expression.Or( _
Expression.Like("Name", "widget"), _
Expression.Like("sku.SkuCode", "wd_"))) _
.List()


Certainly not the way I'd expect a "highly intuitive", productivity-enhancing framework to function. Not by a long shot.

I could have done the required work by creating a couple of custom data handling objects and accompanying T-SQL stored procedures in about ten minutes. To do the same thing in nHibernate has taken two days. What's that about enhancing productivity?

8 comments:

  1. You should read the documentation before starting using a frameword. Even more, before starting complaining about it. And even much more, before calling it stupid.
    Also, you should know about the learning curve of using any new framework.

    ReplyDelete
  2. Stop complaining and start here:

    http://nhforge.org/doc/nh/en/index.html

    ReplyDelete
  3. I did in fact read the documentation before I started. But personally I find it hard to hold the entirety of a product documentation in my head in one go, especially when starting out. And that's pretty much my understanding of "intuitive" - that it should be easy to pick up off a relatively small base of knowledge. nHibernate is touted by its proponents as being "intuitive" but I simply don't find it so.

    But it obviously offers plenty of other benefits so I will persevere. The "stupid" comment is an expression of frustration more than anything else.

    ReplyDelete
  4. Yeah, but it´s intuitive for people that think "object oriented". If you try to understand any orm from the data perspective, it would be like a child trying to put a square figure into a circular shape.

    ReplyDelete
  5. Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
    .Add(Expression.Or( _
    Expression.Like("Name", "widget"), _
    Expression.Like("SkuCode", "wd_"))) _
    .List()

    I don't find this intuitive. Where do you tell him the SkuCode is in the sku association? What if there where two tables linked each one with a SkuCode property how would he know which one you are intuitively thinking of?

    I would expect it to fail telling me SkuCode is not in Product class. And no, I don't know too much about criteria.

    ReplyDelete
  6. If you want it to be more intuitive, you could start by using HQL, so you could read it more fluently than criteria:

    session.CreateQuery("from Product p join p.Skus s where p.Name like :productName or s.SkuCode like :skuCode").SetParameter("productName", "%widget%").SetParameter("skuCode", "%wd_%").List();

    ReplyDelete
  7. @ivowiblo

    Interesting comment. I've done plenty of OO programming with old style data interfaces: i.e. typed data sets and the like, so I can certainly see things from an OO point of view. But I'm not used to seeing data from this view. Perhaps that's the problem, I don't know.

    ReplyDelete
  8. @GLM

    OK, well from my point of view it looks like this. The Fluent mappings mean that when I create a "product" object and do simple read statements, the sku information is included, even though I haven't specified in the nHibernate Expressions that the two tables are linked. But suddenly, when I try and filter on a specific column, the framework requires to be told that the two are linked. Surely it's more intuitive to ensure that the requirements are the same no matter what sort of criteria you want to filter on?

    ReplyDelete