Thanks for your response. You are completely correct.
In double checking my code I realised I had left out some key bits. Please
see below for an updated test case which demonstrates the issue.
Domain classes:
public class House
{
public virtual int id { get; set; }
public virtual Floor ground_floor { get; set; }
public virtual IList<Floor> floors { get; set; }
public House() { floors = new List<Floor>(); }
public House(int id) : this() { this.id = id; }
}
public class Floor
{
public virtual int id { get; set; }
public virtual House house { get; set; }
public virtual Floor_Properties props { get; set; }
public Floor() { }
public Floor(int id) { this.id = id; }
}
Mappings:
<class name="NhComponentLazyLoading.House" table="House">
<id name="id" >
<generator class="assigned" />
</id>
<many-to-one name="ground_floor" column="ground_floor_id" />
<bag name="floors" cascade="all-delete-orphan" inverse="true">
<key column="House_id" />
<one-to-many class="NhComponentLazyLoading.Floor" />
</bag>
</class>
<class name="NhComponentLazyLoading.Floor" table="Floor">
<id name="id">
<generator class="assigned" />
</id>
<many-to-one name="house" column="house_id" />
<component name="props" class="NhComponentLazyLoading.Floor_Properties"
insert="false" lazy="true">
<property name="name" />
</component>
</class>
Test case:
using (var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
var floor = new Floor(1);
session.Save(floor);
var house = new House(1) { ground_floor = floor };
floor.house = house;
session.Save(house);
tx.Commit();
}
using (var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
try
{
var house = session.Get<House>(1);
house.floors.Remove(house.ground_floor);
house.ground_floor = null;
tx.Commit();
}
catch (Exception ex)
{
tx.Rollback();
throw;
}
}
The second commit causes the following exception.
System.InvalidCastException was unhandled
HResult=-2147467262
Message=Unable to cast object of type
'NHibernate.Intercept.UnfetchedLazyProperty' to type
'NhComponentLazyLoading.Floor_Properties'.
Source=NhComponentLazyLoading
StackTrace:
at (Object , GetterCallback )
at
NHibernate.Bytecode.Lightweight.AccessOptimizer.GetPropertyValues(Object
target)
at
NHibernate.Tuple.Component.PocoComponentTuplizer.GetPropertyValues(Object
component)
at NHibernate.Type.ComponentType.GetPropertyValues(Object component,
EntityMode entityMode)
at NHibernate.Type.ComponentType.GetPropertyValues(Object component,
ISessionImplementor session)
at
NHibernate.Engine.ForeignKeys.Nullifier.NullifyTransientReferences(Object
value, IType type)
at
NHibernate.Engine.ForeignKeys.Nullifier.NullifyTransientReferences(Object[]
values, IType[] types)
at
NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource
session, Object entity, EntityEntry entityEntry, Boolean
isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
at
NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent
event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet
transientEntities)
at NHibernate.Impl.SessionImpl.Delete(String entityName, Object
child, Boolean isCascadeDeleteEnabled, ISet transientEntities)
at NHibernate.Engine.Cascade.DeleteOrphans(String entityName,
IPersistentCollection pc)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object
parent, Object child, CollectionType collectionType, CascadeStyle style,
IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object
child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent,
Object child, IType type, CascadeStyle style, Object anything, Boolean
isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object
child, IType type, CascadeStyle style, Object anything, Boolean
isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister,
Object parent, Object anything)
at
NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource
session, IEntityPersister persister, Object key, Object anything)
at
NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource
session)
at
NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent
event)
at
NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
...
Please note that from inspecting the properties in the debugger the
property house.ground_floor.prop is always null on the call to
session.Get<House>(1).
I've also found that if I remove the floor collection mapping from the
House class then I don't get the exception. The issue with this solution is
that cascading deletes don't work for one-to-one or effective one-to-one
relationships in the current version of NHibernate. Therefore I need the
collection mapping to be able to delete child associations without
resorting to session.Delete.
The only solution I have found is to remove lazy="true" from the component
mapping.
Any help would be gratefully appreciated.
Thanks
Michael
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/nhusers?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.