Skip to content

Refresh of locally removed collection item crashes with "instance was not in a valid state" #1738

@RobertSimonsSMA

Description

@RobertSimonsSMA

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>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions