List vs Set vs Bag in NHibernate

What's the difference between a list, set and bag in the NHibernate mapping file? How does each relate to the .NET collections?


Solution 1:

NHibernate semantics:

  1. List: Ordered collection of entities, duplicate allowed. Use a .NET IList in code. The index column will need to be mapped in NHibernate.

  2. Set: Unordered collection of unique entities, duplicates not allowed. Use Iesi.Collection.ISet in code (NH prior to v4) or System.Collections.Generic.ISet (NH v4+). It is important to override GetHashCode and Equals to indicate the business definition of duplicate. Can be sorted by defining an orderby or by defining a comparer resulting in a SortedSet result.

  3. Bag: Unordered list of entities, duplicates allowed. Use a .NET ICollection<T> in code. The index column of the list is not mapped and not honored by NHibernate.

Solution 2:

All of these objects in NHibernate are exactly the same as other implementations of these Abstract Data Types (ADT). I was surprised how hard it is to find Sets and Bags online because of how common the names are for other things, so I've listed some links and descriptions here.

For more detailed information take a look at the following: Lists, Sets and Bags

The general rules are:

Lists are by default ordered, use these if you want to be able to pull out an object by its index or you have a weird fondness of for loops over foreach loops. You aren't required to access them in order like you would need to in a Linked List. This ADT allows duplicates.

Please note! Although lists are ordered as BryanD mentioned in his answer, there is absolutely nothing saying that it has to be in the order you're expecting from the database when you execute a HQL query unless you specify an order by command. It is because of this that some people like to use Set or Bags instead, so that it doesn't give the illusion of being ordered. Though I say this, most of the time they will appear to be in a visible order, as they are added to the list in the order that they are found in the query that NHibernate runs.

Sets are not by default ordered, you cannot access any variable directly via an index. Sets are by default the only ADT out of the above three which maintain uniqueness of its objects. These are great if you have a collection if you require to not contain duplicates.

Bags (or Multisets) are, as you can see from the links above, a type of Set which does allow the objects within it to be duplicates of other objects. These are not generally used, as Lists ordering can be ignored, and hence treated as a Bag.

In relation to how these are used in NHibernate, nothing is pulled from the database differently depending on which ADT you select here, it is what you want to use it for that should make you choose the different ADT.

Personally, I use Sets for most things as I generally require child objects to be unique and ordering is not an issue. Though I will use Lists where I have an group of objects which I want ordered by something, for instance time, to achieve this order I need to manually set the "order by" in the HQL query.