Tuesday, March 25, 2008

Strongly typed NHibernate Criteria with C# 3

I, like many others, hate string literals. Of course, I mean string literals that have some meaning to the code itself, not the "hello, world" kind of strings. They are not type-safe, not easy to refactor, etc. The drawbacks have been mentioned a lot.

In particular, it always bothered me that NHibernate suffers from this problem, specially in the Criteria API. Well, now with C# 3 AST manipulation we can easily fix this. I wrote a simple set of helper classes and extension methods that provide an Expression parameter wherever there was a string parameter describing a property name. Let's see an example:

Instead of writing this:

IList cats = sess.CreateCriteria(typeof(Cat))
    .Add( Expression.Like("Name", "F%")
    .AddOrder( Order.Asc("Name") )
    .AddOrder( Order.Desc("Age") )
    .SetMaxResults(50)
    .List();

You can write this:

IList cats = sess.CreateCriteria(typeof(Cat))
    .Add( ExpressionEx.Like((Cat c) => c.Name, "F%")
    .AddOrder( OrderEx.Asc((Cat c) => c.Name) )
    .AddOrder( OrderEx.Desc((Cat c) => c.Age) )
    .SetMaxResults(50)
    .List();

which is a bit longer, but refactorable.

Code is here (NHibernate 1.2)

UPDATE 2/21/2009: Dan Miser has kindly submitted a patch to port these extensions to NHibernate 2.0.1GA. Code is here. Thanks Dan!

UPDATE 3/28/2010: Two years have passed now since I originally published this and several similar solutions have popped up. In particular, I recommend NH Lambda extensions for NHibernate 2.x which seems to be more complete, less verbose, and better maintained than my own solution. NHibernate 3 will have a new official API similar to this, named QueryOver. If you're stuck with NHibernate 1.2 the only solution available is the one presented in this article.

Related projects:

15 comments:

  1. Have you considered using the NHQG stuff Ayende wrote (I did see you linked to his NHQG article in fact)? You have to buy into the Repository of T stuff (as far as I know) but then you can write stuff like:

    Repository< Cat >.FindAll(Where.Cat.Name.InsensitiveLike("F", MatchMode.Anywhere, OrderBy.Cat.Name.Asc && OrderBy.Cat.Age.Asc)

    ReplyDelete
  2. Dan, I have considered the two projects that I link to. NHQG is a great code generator, but I try to avoid generators whenever I can. LINQ to NHibernate is still being developed and not ready for production AFAIK... So... this is just a lightweight alternative to those two.

    ReplyDelete
  3. Nice feature. But remember that you have to use criteria in dynamics-complex queries. I think that right now isn't a option use criteria instead HQL. When you write the HQL in the mapping NHibernate make a verification (if the HQL is wrong an exception will be thorwn) on BuildSessionFactory time and then the query is cached, this is, parsed once and used forever, and with criteria NH need parse the query every time. On Linq To NHibernate this thing must change...but in a future.

    Best regards

    ReplyDelete
  4. I upgraded the Extensions to the 2.0GA release of NHibernate fairly easily (added namespaces, adjusted Expression.Eq to use Criterion.Expression.Eq, and updated the birhtdate test for my culture).

    If you want me to send a patch, or something else, let me know. dmiser@wi.rr.com.

    Dan

    ReplyDelete
  5. @Dan: by all means, patches are always welcome! I'm sending you a mail

    ReplyDelete
  6. Hi Mauricio. Great stuff, thanks! However, we hit a snag using this. We had the following IQuery:

    from FooBar f where f.Foo.Id = :fooId and f.Bar.Id = :barId

    With this, we tried the following when converting to a criteria search instead:

    .Add( ExpressionEx.Eq((FooBar f) => f.Foo.Id, fooId)

    This mapped to a member name of "Id" though. We've added a fix to your ObjectExtensions class that works here, and would like to ping it your way in case you want to incorporate it. Also, one of your unit tests is locale specific, and will fail in many countries outside the US - we've got a fix
    for that to ping you as well. Drop me an email at david (at) musgroves.us and I'll send them to you.

    David

    ReplyDelete
  7. @davidmus: thanks! I'm sending you a mail

    ReplyDelete
  8. I finally found great post here. Thanks for the information. Please keep sharing more articles.
    토토사이트

    ReplyDelete
  9. Bubble Shooter Games 2 has lots of bubbles, pro color and ball shooting games in 2022. Bubble Shooter Classic is best played with pro friends. Match 3 to pop origin bubbles. This new game is first launched in 2022 game.

    ReplyDelete
  10. Hi there, I enjoy reading all of your article. 슬롯머신

    ReplyDelete
  11. تطهير السجاد باستخدام أحدث التقنيات والمعدات المتطورة. تعتمد شركة كلينر على فريق من الخبراء المدربين الذين يعملون بكفاءة واحترافية لضمان تحقيق أفضل النتائج. تهتم الشركة بتلبية احتياجات العملاء وتقديم خدمات مخصصة تلبي متطلباتهم، مع الالتزام بأعلى معايير الجودة والسلامة. تعتبر شركة كلينر الخيار المثالي لمن يبحث عن خدمات تنظيف موثوقة ومتميزة في الرياض.
    شركة تنظيف سجاد بالرياض

    ReplyDelete
  12. سبيد واي هي شركة نقل عفش بالرياض، تقدم خدمات نقل الأثاث بفعالية وسرعة.
    تشمل خدمات سبيد واي تعبئة وتغليف الأثاث بشكل مناسب لحمايته أثناء النقل، وفك وتركيب الأثاث، بالإضافة إلى توفير سيارات نقل مجهزة لضمان سلامة الأثاث أثناء الرحلة.

    ReplyDelete
  13. أنوار الجنة هي شركة متخصصة في تنظيف السجاد بمدينة سكاكا. تتميز الشركة بتقديم خدمات تنظيف السجاد بأعلى مستويات الجودة والاحترافية، باستخدام تقنيات حديثة ومعدات متطورة لضمان إزالة الأوساخ والبقع بكفاءة. يعتمد فريق عمل أنوار الجنة على خبرتهم الواسعة في مجال تنظيف السجاد، مما يضمن الحصول على نتائج متميزة ورضا العملاء. شركة تنظيف سجاد بسكاكا

    ReplyDelete
  14. شركة حور كلين هي شركة متخصصة في تنظيف الفلل في الرياض، وتتمتع بسمعة مرموقة في تقديم خدمات تنظيف عالية الجودة وشاملة ، تهتم الشركة بتفاصيل العمل لضمان بيئة نظيفة وصحية في الفلل، وتحرص على استخدام منتجات تنظيف آمنة وفعالة. شركة تنظيف فلل بالرياض

    ReplyDelete
  15. تشمل خدمات شركة النور تسليك المجاري بالضغط، تنظيف خطوط الصرف، وصيانة أنظمة الصرف الصحي. تلتزم الشركة بتقديم خدمات عالية الجودة وبأسعار تنافسية، مع الحرص على الاستجابة السريعة لاحتياجات العملاء وتقديم حلول فعالة للمشكلات التي يواجهونها.
    شركة تسليك مجاري بالضغط بالدمام

    ReplyDelete