Tuesday, August 2, 2011

Upgrade to NHibernate 3.2.0

Last days I have worked on upgrading our projects from NH 2.1.2 to a fresh 3.2.0. I am not going to write here about new features and all changes. You can read it in release notes. But I will list what changes I was need to do in an existing code that was written with NH 2.1.2.
1. Now only two dlls referenced. No more log4net, proxy factories (in my case it is Castle), antlr3 and external LINQ provider. That’s good. But why they till now depends on Iesi.Collections?
2. NHibernate session factory configuration section become a little thinner: “proxyfactory.factory_class” and “use_outer_join” should be deleted.
3. I am very happy with a new LINQ provider but this is a little annoying to replace every where Linq<T>() with Query<T>().
4. In old LINQ for eager loading was used Expand() method.
  1. var query = session.Linq<ActionItem>();
  2. query.Expand("Options");
  3. query.Expand("Options.Dependants");
  4. var actions = query.Where(a => a.Event.ID == eventID).ToList();

And now with NH 3.2 it should be replaced with four new methods: Fetch(), ThenFetch(), FetchMany() and ThanFetchMany().
  1. var actions = session.Query<ActionItem>()
  2.     .Where(a => a.Event.ID == eventID)
  3.     .FetchMany(a => a.Options)
  4.         .ThenFetchMany(o => o.Dependants)
  5.     .ToList();

Tried it with QueryOver method. This is an ugly one :)
  1. Option optionAlias = null;
  2. ActionItem actionAlias = null;
  3. ActionItem dependantAlias = null;
  5. var actions = session.QueryOver<ActionItem>(() => actionAlias)
  6.     .Where(a => a.Event.ID == eventID)
  7.     .Left.JoinAlias(() => actionAlias.Options, () => optionAlias)
  8.     .Left.JoinAlias(() => optionAlias.Dependants, () => dependantAlias)
  9.     .TransformUsing(Transformers.DistinctRootEntity)
  10.     .List();

But in one case I had a little more complex scenario. I need to load all action items (and their content) of specified event. Some action items are composite and depends on other action items. So to prevent N+1 problem fetching composite action item’s dependencies I have to join action items table with itself on DependsOn field.
With an old LINQ it works fine:
  1. var query = session.Linq<ActionItem>();
  2. query.Expand("Options");
  3. query.Expand("Options.Dependants");
  4. query.Expand("DependsOn");
  5. var actions = query.Where(a => a.Event.ID == eventID).ToList();

But this is impossible (or I did not achieved how to do it) with a new LINQ and QueryOver.
So I forced to use an old and good IQriteria:
  1. var actions = session.CreateCriteria<ActionItem>()
  2.     .Add(Restrictions.Eq("Event.ID", eventID))
  3.     .SetFetchMode("Options", FetchMode.Eager)
  4.     .SetFetchMode("Options.Dependants", FetchMode.Eager)
  5.     .SetFetchMode("DependsOn", FetchMode.Eager)
  6.     .SetResultTransformer(new DistinctRootEntityResultTransformer())
  7.     .List<ActionItem>();

No comments:

Post a Comment