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:
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:
ReplyDeleteRepository< Cat >.FindAll(Where.Cat.Name.InsensitiveLike("F", MatchMode.Anywhere, OrderBy.Cat.Name.Asc && OrderBy.Cat.Age.Asc)
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.
ReplyDeleteNice 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.
ReplyDeleteBest regards
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).
ReplyDeleteIf you want me to send a patch, or something else, let me know. dmiser@wi.rr.com.
Dan
@Dan: by all means, patches are always welcome! I'm sending you a mail
ReplyDeleteHi Mauricio. Great stuff, thanks! However, we hit a snag using this. We had the following IQuery:
ReplyDeletefrom 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
@davidmus: thanks! I'm sending you a mail
ReplyDeleteI finally found great post here. Thanks for the information. Please keep sharing more articles.
ReplyDelete토토사이트
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.
ReplyDeleteHi there, I enjoy reading all of your article. 슬롯머신
ReplyDeleteتطهير السجاد باستخدام أحدث التقنيات والمعدات المتطورة. تعتمد شركة كلينر على فريق من الخبراء المدربين الذين يعملون بكفاءة واحترافية لضمان تحقيق أفضل النتائج. تهتم الشركة بتلبية احتياجات العملاء وتقديم خدمات مخصصة تلبي متطلباتهم، مع الالتزام بأعلى معايير الجودة والسلامة. تعتبر شركة كلينر الخيار المثالي لمن يبحث عن خدمات تنظيف موثوقة ومتميزة في الرياض.
ReplyDeleteشركة تنظيف سجاد بالرياض
سبيد واي هي شركة نقل عفش بالرياض، تقدم خدمات نقل الأثاث بفعالية وسرعة.
ReplyDeleteتشمل خدمات سبيد واي تعبئة وتغليف الأثاث بشكل مناسب لحمايته أثناء النقل، وفك وتركيب الأثاث، بالإضافة إلى توفير سيارات نقل مجهزة لضمان سلامة الأثاث أثناء الرحلة.
أنوار الجنة هي شركة متخصصة في تنظيف السجاد بمدينة سكاكا. تتميز الشركة بتقديم خدمات تنظيف السجاد بأعلى مستويات الجودة والاحترافية، باستخدام تقنيات حديثة ومعدات متطورة لضمان إزالة الأوساخ والبقع بكفاءة. يعتمد فريق عمل أنوار الجنة على خبرتهم الواسعة في مجال تنظيف السجاد، مما يضمن الحصول على نتائج متميزة ورضا العملاء. شركة تنظيف سجاد بسكاكا
ReplyDeleteشركة حور كلين هي شركة متخصصة في تنظيف الفلل في الرياض، وتتمتع بسمعة مرموقة في تقديم خدمات تنظيف عالية الجودة وشاملة ، تهتم الشركة بتفاصيل العمل لضمان بيئة نظيفة وصحية في الفلل، وتحرص على استخدام منتجات تنظيف آمنة وفعالة. شركة تنظيف فلل بالرياض
ReplyDeleteتشمل خدمات شركة النور تسليك المجاري بالضغط، تنظيف خطوط الصرف، وصيانة أنظمة الصرف الصحي. تلتزم الشركة بتقديم خدمات عالية الجودة وبأسعار تنافسية، مع الحرص على الاستجابة السريعة لاحتياجات العملاء وتقديم حلول فعالة للمشكلات التي يواجهونها.
ReplyDeleteشركة تسليك مجاري بالضغط بالدمام