Checking if an Unloaded Collection Contains Elements with NHibernate

If you want to know if an unloaded collection in an entity contains elements, or count them, without actually loading them, you need to use a custom query; that is because the Count property (if the collection is not mapped with lazy=”extra”) and the LINQ Count() and Any() methods force the whole collection to be loaded.

You can use something like these two methods, one for checking if there are any values, the other for actually counting them:

   1: public static Boolean Exists(this ISession session, IEnumerable collection)
   2: {
   3:     if (collection is IPersistentCollection)
   4:     {
   5:         IPersistentCollection col = collection as IPersistentCollection;
   6:  
   7:         if (col.WasInitialized == false)
   8:         {
   9:                 String[] roleParts = col.Role.Split('.');
  10:                 String ownerTypeName = String.Join(".", roleParts, 0, roleParts.Length - 1);
  11:                 String ownerCollectionName = roleParts.Last();
  12:                 String hql = "select 1 from " + ownerTypeName + " it where it.id = :id and exists elements(it." + ownerCollectionName + ")";
  13:                 Boolean exists = session.CreateQuery(hql).SetParameter("id", col.Key).List().Count == 1;
  14:  
  15:                 return (exists);
  16:         }
  17:     }
  18:  
  19:     return ((collection as IEnumerable).OfType<Object>().Any());
  20: }
  21:  
  22: public static Int64 Count(this ISession session, IEnumerable collection)
  23: {
  24:     if (collection is IPersistentCollection)
  25:     {
  26:         IPersistentCollection col = collection as IPersistentCollection;
  27:  
  28:         if (col.WasInitialized == false)
  29:         {
  30:             String[] roleParts = col.Role.Split('.');
  31:             String ownerTypeName = String.Join(".", roleParts, 0, roleParts.Length - 1);
  32:             String ownerCollectionName = roleParts.Last();
  33:             String hql = "select count(elements(it." + ownerCollectionName + ")) from " + ownerTypeName + " it where it.id = :id";
  34:             Int64 count = session.CreateQuery(hql).SetParameter("id", col.Key).UniqueResult<Int64>();
  35:  
  36:             return (count);
  37:         }
  38:     }
  39:  
  40:     return ((collection as IEnumerable).OfType<Object>().Count());
  41: }

Here’s how:

   1: MyEntity entity = session.Load(100);
   2:  
   3: if (session.Exists(entity.SomeCollection))
   4: {
   5:     Int32 count = session.Count(entity.SomeCollection);
   6:     //...
   7: }

                             

No Comments