-
Notifications
You must be signed in to change notification settings - Fork 936
Closed
Description
When removing an item from a mapped collection in one ISession, and refreshing the collection state in another session NHibernate crashes with "instance was not in a valid state".
Crash was reproduced in NHibernate 4.0.x
Code snippet to reproduce the crash:
DataItemWithSubItems item;
using (ISession session = sessionFactory.OpenSession()) {
item = session.Get<DataItemWithSubItems>(1);
Assert.That(item.SubItems.Count, Is.EqualTo(3));
Assert.That(item.SubItems[0].Name, Is.EqualTo("Name 101"));
Assert.That(item.SubItems[1].Name, Is.EqualTo("Name 102"));
Assert.That(item.SubItems[2].Name, Is.EqualTo("Name 103"));
item.SubItems.RemoveAt(1);
Assert.That(item.SubItems.Count, Is.EqualTo(2));
}
using (ISession session = sessionFactory.OpenSession()) {
session.Update(item);
session.Refresh(item);
foreach (var rawItem in item.SubItems) {
session.Refresh(rawItem); // <-- it crashes here.
}
Assert.That(item.SubItems.Count, Is.EqualTo(3));
Assert.That(item.SubItems[0].Name, Is.EqualTo("Name 101"));
Assert.That(item.SubItems[1].Name, Is.EqualTo("Name 102"));
Assert.That(item.SubItems[2].Name, Is.EqualTo("Name 103"));
}
Stacktrace:
NHibernate.HibernateException : instance was not in a valid state
bei NHibernate.Engine.EntityEntry.get_IsReadOnly() in d:\Projects\NHibernate\nhibernate-core\src\NHibernate\Engine\EntityEntry.cs:Zeile 293.
bei NHibernate.Event.Default.DefaultRefreshEventListener.OnRefresh(RefreshEvent event, IDictionary refreshedAlready) in d:\Projects\NHibernate\nhibernate-core\src\NHibernate\Event\Default\DefaultRefreshEventListener.cs:Zeile 115.
bei NHibernate.Impl.SessionImpl.FireRefresh(RefreshEvent refreshEvent) in d:\Projects\NHibernate\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:Zeile 2492.
bei NHibernate.Impl.SessionImpl.Refresh(Object obj) in d:\Projects\NHibernate\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:Zeile 1379.
[User Code]
Workaround: use own IRefreshEventListener that does not evaluate EntityEntry.IsReadOnly for the locally deleted item.
mapped classes:
public class DataItemWithSubItems {
public int SID { get; private set; }
public string Name { get; set; }
public IList<SubItem> SubItems { get; private set; }
}
public class SubItem {
public int SID { get; private set; }
public string Name { get; set; }
public DataItemWithSubItems Parent { get; private set; }
}
Mapping files:
<class name="NHibernateRefreshEventListener.DataItemWithSubItems, NHibernateRefreshEventListener" table="MAIN_TABLE" dynamic-update="true" lazy="false">
<id name="SID" type="Int32" column="SID" unsaved-value="-1">
<generator class="hilo" />
</id>
<property name="Name" column="NAME" length="50" not-null="false"/>
<bag
name="SubItems" inverse="true" lazy="false" cascade="all-delete-orphan">
<key column="PARENT_SID"/>
<one-to-many class="NHibernateRefreshEventListener.SubItem, NHibernateRefreshEventListener" />
</bag>
</class>
<class name="NHibernateRefreshEventListener.SubItem, NHibernateRefreshEventListener" table="SUB_TABLE" dynamic-update="true" lazy="false">
<id name="SID" type="Int32" column="SID" unsaved-value="-1">
<generator class="hilo" />
</id>
<property name="Name" column="NAME" length="50" not-null="false"/>
<many-to-one name="Parent" class="NHibernateRefreshEventListener.DataItemWithSubItems, NHibernateRefreshEventListener" column="PARENT_SID" />
</class>