Uploaded image for project: 'NHibernate [Moved to GitHub]'
  1. NH-1477

Saving a collection (thats been Cleared) with all-delete-orphan using Oracle with ODP drivers

    Details

    • Sprint:

      Description

      The bug only happens with Oracle using the odp drivers. It's fine with SQL Server, or Oracle using the microsoft driver.

      Full stack trace of any exception that occurs:
      System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
      Parameter name: index
      at System.Collections.ArrayList.get_Item(Int32 index)
      at Oracle.DataAccess.Client.OracleParameterCollection.GetParameter(Int32 index)
      at System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index)
      at NHibernate.Type.Int32Type.Set(IDbCommand rs, Object value, Int32 index)
      at NHibernate.Type.NullableType.NullSafeSet(IDbCommand cmd, Object value, Int32 index)
      at NHibernate.Type.NullableType.NullSafeSet(IDbCommand st, Object value, Int32 index, ISessionImplementor session)
      at NHibernate.Persister.Collection.AbstractCollectionPersister.WriteKey(IDbCommand st, Object id, Int32 i, ISessionImplementor session)
      at NHibernate.Persister.Collection.AbstractCollectionPersister.InsertRows(IPersistentCollection collection, Object id, ISessionImplementor session)
      at NHibernate.Action.CollectionUpdateAction.Execute()
      at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
      at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
      at NHibernate.Engine.ActionQueue.ExecuteActions()
      at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
      at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
      at NHibernate.Impl.SessionImpl.Flush()
      at Persistence.Repository.Save(Object obj) in Repository.cs: line 49

      To recreate it

      Create a class (called "View") which contains the following mapping to a class "Field"

      <list name="Fields" fetch="join" cascade="all-delete-orphan" lazy="false">
      <key column="ViewID" foreign-key="fk_ViewID"></key>
      <index column="fieldorder" />
      <one-to-many class="Field"/>
      </list>

      then use some code like

      View view = new View();

      IField field = Factory.NewField("test" + Guid.NewGuid());
      view.fields.add(field);
      Repository.Save(view);

      View viewFromDB = Repository.GetView(view.ID);
      viewFromDB .fields.Clear();

      IField field2 = Factory.NewField("test" + Guid.NewGuid());
      viewFromDB.fields.add(field);
      viewFromDB.fields.add(field2);

      Repository.Save(viewFromDB);

      I populate the collection, then save the parent.
      Get the parent back from the database, then call .Clear; on the collection, and resave the parent.

      I've stepped through the code and the problem seems to be with the dispose method of the oracleCommand object clearing the parameters collection. (when using other drivers the dispose method is called, but it doesn't clear the collection)

      But I would think that the fact that it's reusing the command after it's attempted to close it is the actual bug. If the command was set to null it would recreate it properly.

      I can work around it by clearing the collection, saving, then adding more items, but this isn't satisfactory.

        Attachments

          Issue links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                jonspokes Jon Spokes
              • Votes:
                2 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Who's Looking?