Invalid case of Collection or HashSet to ISet exception on save

618 views
Skip to first unread message

Graham Bunce

unread,
Jun 30, 2010, 10:35:36 AM6/30/10
to nhusers
All,

I've come across an odd situation with NH and the Version settings. My
App uses generic ICollections and map these to sets. It works fine
without any problems.

However, if i add the Version setting to the mapping file I get
intermittent problems such as:

Unable to cast object of type
'System.Collections.ObjectModel.Collection`1[Entities.Allocation.OrderItem]'
to type 'Iesi.Collections.ISet'.

This occurs when I perform a save of the root object (the order) then
flush. The Order has the version setting, not the Order Item.

Our C# is (e.g.)

private ICollection<OrderItem> _orderItems;

initialised via:

_orderItems = new Collection<OrderItem>();

in the constructor of the class.

I'm going off the post from Ayende where he states you don't need to
use IESI.Collections any more (I used to have " _orderItems = new
HashSet<OrderItem>(); " as suggested, but that fell over too with
something similar to "cannot cast HashSet to type
'Iesi.Collections.ISet'. "

http://ayende.com/Blog/archive/2009/04/23/nhibernate-tidbit-ndash-using-ltsetgt-without-referencing-iesi.collections.aspx

The code works fine if I don't use Version, but then I'll have to roll
my own, which sort of defeats the point.

Snipped mapping file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Entities.Allocation"
assembly="Domain"
default-access="field.camelcase-underscore"
default-lazy="true">

<class name="Order" table="Allocation.[Order]">
<id name="Id" column="Id" type="int" unsaved-value="0">
<generator class="hilo">
<param name="max_lo">2</param>
<param name="where">Entity='Order'</param>
</generator>
</id>
<version name="Version" column="Version" type="int" />
.....

<set name="OrderAllocations" table="Allocation.OrderAllocation"
inverse="true" cascade="all-delete-orphan" >
<key column="OrderId" />
<one-to-many class="OrderAllocation" />
</set>

</class>
</hibernate-mapping>

José F. Romaniello

unread,
Jun 30, 2010, 11:21:10 AM6/30/10
to nhu...@googlegroups.com
let me guess... It works with Version & HashedSet (from iesi.)

2010/6/30 Graham Bunce <graha...@hotmail.com>

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.


Fabio Maulo

unread,
Jun 30, 2010, 11:22:49 AM6/30/10
to nhu...@googlegroups.com
On Wed, Jun 30, 2010 at 12:21 PM, José F. Romaniello <jfroma...@gmail.com> wrote:
let me guess... It works with Version & HashedSet (from iesi.)

Noooooooo... really ?

ROTFL!!!

-- 
Fabio Maulo

José F. Romaniello

unread,
Jun 30, 2010, 11:52:31 AM6/30/10
to nhu...@googlegroups.com
Yes, I have mental powers.

OTOH; I know where is the official documentation; http://nhforge.org/doc/nh/en/index.html#collections 




2010/6/30 Fabio Maulo <fabio...@gmail.com>

--

Graham Bunce

unread,
Jun 30, 2010, 12:51:18 PM6/30/10
to nhusers
Thanks for the "answers".

As I said in my post, it also fails if I use HashSet AS PER AYENDE'S
POST

Unable to cast object of type
'System.Collections.Generic.HashSet`1[iTrace.Domain.Entities.Operation.MovementTransactionItem]'
to type 'Iesi.Collections.ISet'.

You telling me we MUST use the IESI HashedSet then?

José F. Romaniello

unread,
Jun 30, 2010, 2:59:46 PM6/30/10
to nhu...@googlegroups.com
I am not sure about this but the main problem is that the .Net Framework provides HashSet in version 3.5;

but they didn't provide the INTERFACE.... until .net 4:


When you retrieve an instance of your object from nhibernate, you don't get a HashSet in the field, you get something like a PersistentGenericSet (an implementation of the interface that is nh internals).

So, i think is not possible to replace iesi hashedset with hashset so far.

Fabio Maulo

unread,
Jun 30, 2010, 3:11:29 PM6/30/10
to nhu...@googlegroups.com
More than that José, the matter is the interface.
when you write <set> in the mapping NH will expect an implementation of Iesi.Collections.ISet

For NH4, perhaps, we can introduce the ASTRONOMIC breaking change giving support to System.Collections.Generic.ISet<T> instead Iesi and replacing the Iesi.ISet (no generic) with a System.Collections.Generic.ISet<object>
.....
and God save the Queen and somebody pray for us.

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.



--
Fabio Maulo

Fabio Maulo

unread,
Jun 30, 2010, 3:14:16 PM6/30/10
to nhu...@googlegroups.com
On Wed, Jun 30, 2010 at 1:51 PM, Graham Bunce <graha...@hotmail.com> wrote:

You telling me we MUST use the IESI HashedSet then?



The expected implementation for <set> is ISet (that mean Iesi.Collection).  
--
Fabio Maulo

Graham Bunce

unread,
Jun 30, 2010, 4:45:29 PM6/30/10
to nhusers
Fabio,

Thank you for the more helpful update and link to JIRA. Perhaps Ayende
can update that blog entry to say that actually you CAN'T use HashSet
and must still use the Iesi HashedSet.

Although it will be a bit of an OMG change for .NET 4.0, it would be
nice as (hopefully) it will enable greater flexibility in the future
for repository -> model layers (i.e NH or EF). I can understand how it
could be a big change for little gain - from NH's perspective anyway.

Fabio Maulo

unread,
Jul 1, 2010, 12:16:22 AM7/1/10
to nhu...@googlegroups.com
We will change NH, no problem.
Btw I can't understand the problem with Iesi.Collections; it is a set
of collection exactly as System.Collection... Which is the problem ?


--
Fabio Maulo

Graham Bunce

unread,
Jul 1, 2010, 4:56:21 AM7/1/10
to nhusers
Fabio - I know what you mean and I'm coming to the state of mind of
"I'm a bit fed up of trying to seperate repository from domain so just
go with it".

However the problem is that although iesi is open source and is not an
NH specific dll, it's not a BCL collection. So far I've strictly
enforced domain and repository seperation - even handy NH commmands
such as Unproxy are wrapped in a generic way so if I choose to move my
repository from NH to EF, to an XML based repository or anything else
then I know I'm using BCL stuff so most things have a higher chance of
being ok.

If I ever decide to move to EF then it will be populating my
collections instead of NH, and it most definitely will not use iesi
but probably a Collection<T> or a HashSet<T>. If my domain layer only
uses ICollection<T> (which from what I understand from the JIRA I
still can) and one of these other collections for initialisation, then
I have more chance of doing a drop-in replacement of my NH repository
with an EF one when the time eventually comes. If EF blows up in the
same way NH does over iesi HashedSet<T> then I have to change my
domain layer and seperation is lost.

I accept it's almost an esoteric argument (hence why I'm almost at the
stage of giving up and going with iesi) but it's a quite important
principle that I (and I'm sure many others) are loathe to surrender
without a good fight.

Oskar Berggren

unread,
Jul 1, 2010, 5:16:07 AM7/1/10
to nhu...@googlegroups.com
2010/7/1 Graham Bunce <graha...@hotmail.com>:

> Fabio - I know what you mean and I'm coming to the state of mind of
> "I'm a bit fed up of trying to seperate repository from domain so just
> go with it".

Maybe we mean different thing with "repository", but I consider the
repository concept (not necessarily the implementation) to be part of
the domain model.


> However the problem is that although iesi is open source and is not an
> NH specific dll, it's not a BCL collection. So far I've strictly
> enforced domain and repository seperation - even handy NH commmands
> such as Unproxy are wrapped in a generic way so if I choose to move my
> repository from NH to EF, to an XML based repository or anything else
> then I know I'm using BCL stuff so most things have a higher chance of
> being ok.

Doesn't EF have special collections classes also? Or is it just
Linq2SQL that require those?

> If I ever decide to move to EF then it will be populating my
> collections instead of NH, and it most definitely will not use iesi
> but probably a Collection<T> or a HashSet<T>. If my domain layer only
> uses ICollection<T> (which from what I understand from the JIRA I
> still can) and one of these other collections for initialisation, then
> I have more chance of doing a drop-in replacement of my NH repository
> with an EF one when the time eventually comes. If EF blows up in the
> same way NH does over iesi HashedSet<T> then I have to change my
> domain layer and seperation is lost.

ICollection<T> as interface.
Domain classes instantiating collection will do
SomeClass-ctor():
MyColl = CollectionFactory.CreateDefaultSet()

So you have one place to change if needed, or even use a pluggable
collection provider behind the static CollectionFactory.

> I accept it's almost an esoteric argument (hence why I'm almost at the
> stage of giving up and going with iesi) but it's a quite important
> principle that I (and I'm sure many others) are loathe to surrender
> without a good fight.
>


/Oskar

Fabio Maulo

unread,
Jul 1, 2010, 8:57:41 AM7/1/10
to nhu...@googlegroups.com
The work to implement something give full support to
System.Collection.Generic.ISet<T> is completelly possible right now.
NH has a injectable CollectionFactory where you can any
IPersistentCollectionXyz required by NH. In this moment we can't do it
directly in NH because this mean .NET4 as requirement.

If you realy need it, you can do it ;)
An example of CollectionFactory is available in uNhAddIns where we
have implemented it for ObservableCollection to work with WPF (even
collections coming from NH are observable).

--
Fabio Maulo

Graham Bunce

unread,
Jul 1, 2010, 9:38:14 AM7/1/10
to nhusers
Oskar
:
>Maybe we mean different thing with "repository", but I consider the repository concept (not necessarily the implementation) to be part of the domain model.

No I don't think we do. My domain layer uses BCL collections and
accesses my repository through an interface. The only rule my
repository must adhere to is that it supports implicit Lazy loading,
or we accept we are working in a non-lazy load environment (e.g. an
pure ADO.NET implementation of the repository). In reality, the latter
is something we'll never do, but it's an option.

My repository provides results through ICollection<T> but also does
its implicit Lazy Loading against an ICollection<T> interface.
Therefore no dependency on NH or Iesi in the domain layer.

>So you have one place to change if needed, or even use a pluggable collection provider behind the static CollectionFactory.

yep, I thought of this too. It's actually not a bad idea tbh - it does
mean the programmer has to know not to create collections themselves
(principle of least surprise), but the more I think about it, its not
a major issue and is easy to refactor in.

>Doesn't EF have special collections classes also? Or is it just Linq2SQL that require those?

L2SQL does, EF did (I think). I believe it doesn't have to now, but
even so, it's not a decision I'd take until at least EF 5.0 as it's
still not up to NH's standard. Sooner or later though it will be and
it's my job to ensure the code in our company can be migrated forward
as technology changes.


Fabio:

>The work to implement something give full support to System.Collection.Generic.ISet<T> is completelly possible right now.

Ok, this is something I'll look into. If I can abstract it away or
make it configurable somehow within my repository layer then that's
the best solution. Just to be clear though, I still want to use
ICollection<T> in my domain model but am happy to use HashedSet<T> by
whatever means I create it. HashedSet<T> implements ICollection<T> so
I should be fine. Is that correct?

Fabio Maulo

unread,
Jul 1, 2010, 9:55:49 AM7/1/10
to nhu...@googlegroups.com
On Thu, Jul 1, 2010 at 10:38 AM, Graham Bunce <graha...@hotmail.com> wrote:

Fabio:

>The work to implement something give full support to System.Collection.Generic.ISet<T> is completelly possible right now.

Ok, this is something I'll look into. If I can abstract it away or
make it configurable somehow within my repository layer then that's
the best solution. Just to be clear though, I still want to use
ICollection<T> in my domain model but am happy to use HashedSet<T> by
whatever means I create it. HashedSet<T> implements ICollection<T> so
I should be fine. Is that correct?


What ?
Perhaps I was not clear.
You don't need to do something neither with your repository nor your domain. You can do it externally implementing  ICollectionTypeFactory and injecting it to NHibernate through NH's configuration.... "nothing more"

The example I'm talking about is in : uNhAddIns\trunk\uNhAddIns\uNhAddIns.WPF\Collections
--
Fabio Maulo

Fabio Maulo

unread,
Jul 1, 2010, 10:04:40 AM7/1/10
to nhu...@googlegroups.com
On Thu, Jul 1, 2010 at 10:38 AM, Graham Bunce <graha...@hotmail.com> wrote:

>Doesn't EF have special collections classes also? Or is it just  Linq2SQL that require those?

L2SQL does, EF did (I think). I believe it doesn't have to now, but
even so, it's not a decision I'd take until at least EF 5.0 as it's
still not up to NH's standard. Sooner or later though it will be and
it's my job to ensure the code in our company can be migrated forward
as technology changes.


"forward".... well... "forward" is a mere hope in some cases. I saw somebody trying to go from NH to EF and "forward" is not exactly his feeling.

--
Fabio Maulo

Graham Bunce

unread,
Jul 1, 2010, 10:13:53 AM7/1/10
to nhusers
>"forward".... well... "forward" is a mere hope in some cases.
lol. That's is certainly true. We can hope though...

>I saw somebody trying to go from NH to EF and "forward" is not exactly his feeling.
Well, EF is a non starter at the moment but it's something that senior
managers keep questioning me about so I have to keep tabs on it at
least.

Cheers anyway.

José F. Romaniello

unread,
Jun 30, 2010, 3:39:32 PM6/30/10
to nhu...@googlegroups.com
Good to know, to be honest... never bothered me to have a reference to iesi.

2010/6/30 Fabio Maulo <fabio...@gmail.com>

Graham Bunce

unread,
Jul 2, 2010, 2:07:43 PM7/2/10
to nhusers
ok... an update to this.

I have a new object. This object has a child collection which is an
intitialised empty iesi hashedset<T>.

Perform a Save on this parent and NH crashes:

Unable to cast object of type
'Iesi.Collections.Generic.HashedSet`1[iTrace.Domain.Entities.LocationOrderDay]'
to type
'System.Collections.Generic.IList`1[iTrace.Domain.Entities.LocationOrderDay]'.

Of course, Hashed Set doesn't implement the IList<T> interface that
the NH Wrap method seems to need..... Any further advice?


at NHibernate.Type.GenericListType`1.Wrap(ISessionImplementor
session, Object collection) at
NHibernate.Event.Default.WrapVisitor.ProcessArrayOrNewCollection(Object
collection, CollectionType collectionType) at
NHibernate.Event.Default.WrapVisitor.ProcessCollection(Object
collection, CollectionType collectionType) at
NHibernate.Event.Default.AbstractVisitor.ProcessValue(Object value,
IType type) at
NHibernate.Event.Default.WrapVisitor.ProcessValue(Int32 i, Object[]
values, IType[] types) at
NHibernate.Event.Default.AbstractVisitor.ProcessEntityPropertyValues(Object[]
values, IType[] types) at
NHibernate.Event.Default.AbstractSaveEventListener.VisitCollectionsBeforeSave(Object
entity, Object id, Object[] values, IType[] types, IEventSource
source) at
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object
entity, EntityKey key, IEntityPersister persister, Boolean
useIdentityColumn, Object anything, IEventSource source, Boolean
requiresImmediateIdAccess) at
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object
entity, Object id, IEntityPersister persister, Boolean
useIdentityColumn, Object anything, IEventSource source, Boolean
requiresImmediateIdAccess) at
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object
entity, String entityName, Object anything, IEventSource source,
Boolean requiresImmediateIdAccess) at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent
event) at
NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent
event) at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent
event) at
NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent
event) at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent
event) at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent
event) at NHibernate.Impl.SessionImpl.Save(Object obj) at
MyApp.NHibernate.Repository.Save(Location item) in ....

Graham Bunce

unread,
Jul 2, 2010, 2:17:04 PM7/2/10
to nhusers
nvm, it had been mapped as a List not a Set. The only one in the
application the be different :p

Fabio Maulo

unread,
Jul 2, 2010, 2:16:35 PM7/2/10
to nhu...@googlegroups.com
my friend... from where you come ?
take it easy and review your mapping... probably you have a ICollection<T> property mapped using <bag> but you are instancing a Iesi.HashedSet<T>...

Perhaps I know who is the responsible... perhaps I know from where you come to NHibernate.

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.




--
Fabio Maulo

Reply all
Reply to author
Forward
0 new messages