Querying an Uninitialized Collection with NHibernate

I have talked before about the problem of accessing an uninitialized collection and presented a solution that allows us to see if the collection contains elements on the DB, and how many there are, without actually loading them. Now I have a general purpose solution for querying the collection on the DB.

Here it is:

   1: public static IQueryable<T> Query<T>(this IEnumerable<T> collection)
   2: {
   3:     if (collection is AbstractPersistentCollection)
   4:     {
   5:         IPersistentCollection col = collection as IPersistentCollection;
   6:  
   7:         if (col.WasInitialized == false)
   8:         {
   9:             String role = col.Role;
  10:             Object owner = col.Owner;
  11:             Object key = col.Key;
  12:             ISessionImplementor sessionImpl = typeof(AbstractPersistentCollection).GetField("session", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(collection) as ISessionImplementor;
  13:             ISession session = sessionImpl as ISession;
  14:             ISessionFactory sessionFactory = session.SessionFactory;
  15:             String ownerEntityName = sessionImpl.BestGuessEntityName(owner);
  16:             Type ownerType = Type.GetType(ownerEntityName);
  17:             IClassMetadata metadata = sessionFactory.GetClassMetadata(ownerEntityName);
  18:             String idPropertyName = metadata.IdentifierPropertyName;
  19:             MethodInfo ownerIdGetMethod = ownerType.GetProperty(idPropertyName).GetGetMethod();
  20:             String childPropertyName = role.Split('.').Last();
  21:             MethodInfo ownerChildGetMethod = ownerType.GetProperty(childPropertyName).GetGetMethod();
  22:             Type childType = typeof(T);
  23:             ParameterExpression a = null;
  24:             IQueryable<T> details = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "SelectMany" && x.GetParameters().Length == 2).First().MakeGenericMethod(ownerType, childType).Invoke
  25:             (
  26:                 null,
  27:                 new Object[]
  28:                     {                    
  29:                         typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "Where").First().MakeGenericMethod(ownerType).Invoke
  30:                         (
  31:                             null,
  32:                             new Object[]
  33:                             {
  34:                                 typeof(LinqExtensionMethods).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(x => x.Name == "Query" && x.GetParameters()[0].ParameterType == typeof(ISession)).Single().MakeGenericMethod(ownerType).Invoke
  35:                                 (
  36:                                     null,
  37:                                     new Object [] { session }
  38:                                 ),
  39:                                 Expression.Lambda
  40:                                 (
  41:                                     typeof(Func<,>).MakeGenericType(ownerType, typeof(Boolean)),
  42:                                     Expression.Equal(Expression.Property(a = Expression.Parameter(ownerType, "x"), ownerIdGetMethod), Expression.Constant(key, ownerIdGetMethod.ReturnType)), new ParameterExpression[] { a }
  43:                                 )
  44:                             }
  45:                         ),
  46:                         Expression.Lambda
  47:                         (
  48:                             typeof(Func<,>).MakeGenericType(ownerType, typeof(IEnumerable<>).MakeGenericType(childType)),
  49:                             Expression.Property(a = Expression.Parameter(ownerType, "x"), ownerChildGetMethod), new ParameterExpression[] { a }
  50:                         )
  51:                     }
  52:             ) as IQueryable<T>;
  53:  
  54:             return (details);
  55:         }
  56:     }
  57:  
  58:     return (collection.AsQueryable());
  59: }

As you can see, I first check to see the collection is an NHibernate one, if not, I fall back to LINQ to Objects; also, if the collection is already initialized, I also use LINQ to Objects.

Hope this helps!

                             

No Comments