Page 1 of 1

why collections typed as HashedSet<T> rather than Set<T> ?

Posted: Tue 20 Dec 2011 22:17
by mindplay
The NH template is hard-coded to generate collections as type Iesi.Collections.Generic.HashedSet<T> ... the problem with this type, is that the iteration order is undefined - whereas Iesi.Collections.Generic.Set<T> maintains iteration order.

This is easy enough to fix in the template of course.

However, defining "Order By" (under "Fetching" on the property sheet in ED) may not give the result you were expecting - I would consider this a bug: if I've specified that the order is important, the collection-type should be Set<T> rather than HashedSet<T>, or else this setting has no meaning.

Ideally, there should be an option to configure the default bag/set collection types. While I realize that HashedSet<T> is faster, personally I prefer Set<T>, as the unpredictable order can make it extremely hard to debug code, as some code may fail periodically or at random...

Posted: Fri 23 Dec 2011 11:30
by Shalex
The generated collection is of the Iesi.Collections.Generic.HashedSet<T> type because NHibernate runtime returns the object of the HashedSet<T> type when you access the element of this collection.

Posted: Wed 28 Dec 2011 13:53
by mindplay
Are you sure that is true, even for collections that have an order-by clause? (How would NH be able to return a sorted collection of nested items, if the collection-type it uses does not maintain order? I looked at the implementation of HashedSet, and it is just a simple wrapper around a Dictionary - both the IESI documentation, and MSDN references, states clearly that the Dictionary type does not maintain order.)

EDIT: the IESI HashedSet type in the source-code in the NH repository uses a different implementation - this is wrapper around Hashtable rather than Dictionary... documentation for HashedSet states that "iteration will occur in no particular order", however, the documentation for Hashtable makes no statements about order, so who knows...?

Posted: Thu 29 Dec 2011 09:57
by Shalex
Please try changing the type of collection in the generated code and check object type that is returned by NHibernate runtime.

Posted: Thu 29 Dec 2011 15:56
by mindplay
As you can see:

https://docs.google.com/open?id=0BxKmkm ... NmNDg5ZmQ3

When you apply an order-by clause to a mapping, NH uses a collection-type that can maintain order.

The other case would be a collection where you care about the order in which the items are added - I'm pretty sure there's a way to do that with NH, and I read somewhere that this requires NH to delete and re-save the entire collection of child-items, so I haven't tried that yet... (I will eventually, as I do have a couple of collections where the user defines the order.)

Posted: Tue 03 Jan 2012 14:46
by Helen
Thank you for your assistance and additional information.
We will fix the issue and inform you when the build containing the fix is published.

Posted: Wed 04 Jan 2012 13:47
by Helen
We have investigated the issue and we would like to determine what exactly does not suit you.

Currently, the following code is generated when initializing the field for the navigation property in the constructor:

Code: Select all

this._Emps = new Iesi.Collections.Generic.HashedSet<Emp>(); 
The type of the _Emps field and the type of the navigation property itself are generated by Iesi.Collections.Generic.ISet<Emp>:

Code: Select all

  public virtual Iesi.Collections.Generic.ISet<Emp> Emps
       {
           get
           {
               return this._Emps;
           }
           set
           {
               this._Emps = value;
           }
       }
   } 
When getting this object, NHibernate runtime initializes the _Emps field again with the required object (PersistentGenericSet<T>, OrderedSet<T> or another one). All these types implement Iesi.Collections.Generic.ISet<Emp> and errors never occur in this case.

As we understood from your first post, it does not suit you that we generate new Iesi.Collections.Generic.HashedSet<Emp>() for the _Emps field initialization in the following code:

Code: Select all

  this._Emps = new Iesi.Collections.Generic.HashedSet<Emp>(); 
And you offer using Iesi.Collections.Generic.Set<T> instead, however it is an abstract class, and it is impossible to create an instance of this class.

Besides, the PersistentGenericSet<T> class, instance of which is created by NHibernate in the standard case is not a descendant of Iesi.Collections.Generic.Set<T> class, and this can cause cast exception.

Posted: Wed 04 Jan 2012 18:42
by mindplay
So HashedSet{T} is not an alternative to Set{T} which is abstract. Thank you for explaining this.

I'm still mixed up about how this would work though.

According to IESI documentation, HashedSet{T} does not guarantee iteration order. So if you initialize a navigation-property as HashedSet{T}, that collection can't maintain order.

After you save the object, NH may replace that property with a new collection of it's own internal type, and that type may have a sense of order - but initially, NH would must populate it's own collection-type from the HashedSet{T} collection you created, in which case, it will iterate that collection in no particular order.

That doesn't cause problems?

Posted: Thu 05 Jan 2012 12:21
by Helen
We will change the behaviour in the following way: the field initialization code will create an object of the type, similar to the internal NHibernate type for this field.

This changed behaviour will be available in the next build. We will inform you when the corresponding build is available.

Posted: Thu 12 Jan 2012 15:25
by Helen
In the latest 4.2.110 build of Entity Developer the field initialization code will create an object of the type, similar to the internal NHibernate type for this field.

The new build can be downloaded from http://www.devart.com/entitydeveloper/download.html (the trial and free versions) or from Registered Users' Area (provided that you have an active subscription).

For the detailed information about the improvements and fixes available in Entity Developer 4.2.110, please refer to
http://www.devart.com/forums/viewtopic.php?t=23135