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

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
Post Reply
mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

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

Post by mindplay » Tue 20 Dec 2011 22:17

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...

Shalex
Site Admin
Posts: 8247
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Fri 23 Dec 2011 11:30

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.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Wed 28 Dec 2011 13:53

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...?

Shalex
Site Admin
Posts: 8247
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Thu 29 Dec 2011 09:57

Please try changing the type of collection in the generated code and check object type that is returned by NHibernate runtime.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Thu 29 Dec 2011 15:56

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.)

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Tue 03 Jan 2012 14:46

Thank you for your assistance and additional information.
We will fix the issue and inform you when the build containing the fix is published.

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Wed 04 Jan 2012 13:47

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.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Wed 04 Jan 2012 18:42

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?

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Thu 05 Jan 2012 12:21

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.

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Thu 12 Jan 2012 15:25

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

Post Reply