From: Michael D. <mik...@us...> - 2004-07-07 05:20:42
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17776/NHibernate/Impl Modified Files: SessionImpl.cs Log Message: Fixed problem with nullifiables field and out of memory exception with cascading deletes and circular references. Index: SessionImpl.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl/SessionImpl.cs,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** SessionImpl.cs 6 Jul 2004 04:35:22 -0000 1.32 --- SessionImpl.cs 7 Jul 2004 05:20:28 -0000 1.33 *************** *** 214,218 **** [NonSerialized] private IdentityMap collections; //key=PersistentCollection, value=CollectionEntry ! private IList nullifiables = new ArrayList(); //set of Keys of deleted objects private IInterceptor interceptor; --- 214,218 ---- [NonSerialized] private IdentityMap collections; //key=PersistentCollection, value=CollectionEntry ! private IDictionary nullifiables = new Hashtable(); //set of Keys of deleted objects private IInterceptor interceptor; *************** *** 1108,1111 **** --- 1108,1112 ---- } + return e.Status==Status.Saving || ( earlyInsert ? !e.ExistsInDatabase : nullifiables.Contains( new Key(e.Id, e.Persister) ) *************** *** 1121,1127 **** if (obj==null) throw new NullReferenceException("attempted to delete null"); ! object theObj = UnproxyAndReassociate(obj); ! EntityEntry entry = GetEntry(theObj); IClassPersister persister=null; if (entry==null) --- 1122,1129 ---- if (obj==null) throw new NullReferenceException("attempted to delete null"); ! //object theObj = UnproxyAndReassociate(obj); ! obj = UnproxyAndReassociate(obj); ! EntityEntry entry = GetEntry(obj); IClassPersister persister=null; if (entry==null) *************** *** 1129,1138 **** log.Debug("deleting a transient instance"); ! persister = GetPersister(theObj); ! object id = persister.GetIdentifier(theObj); if (id==null) throw new HibernateException("the transient instance passed to Delete() has a null identifier"); ! object old = GetEntry( new Key(id, persister) ); if (old!=null) --- 1131,1140 ---- log.Debug("deleting a transient instance"); ! persister = GetPersister(obj); ! object id = persister.GetIdentifier(obj); if (id==null) throw new HibernateException("the transient instance passed to Delete() has a null identifier"); ! object old = GetEntity( new Key(id, persister) ); if (old!=null) *************** *** 1144,1156 **** } ! RemoveCollectionsFor(persister, id, theObj); ! AddEntity( new Key(id, persister), theObj); entry = AddEntry( ! theObj, Status.Loaded, ! persister.GetPropertyValues(theObj), id, ! persister.GetVersion(theObj), LockMode.None, true, --- 1146,1158 ---- } ! RemoveCollectionsFor(persister, id, obj); ! AddEntity( new Key(id, persister), obj); entry = AddEntry( ! obj, Status.Loaded, ! persister.GetPropertyValues(obj), id, ! persister.GetVersion(obj), LockMode.None, true, *************** *** 1171,1178 **** --- 1173,1182 ---- if ( !persister.IsMutable ) + { throw new HibernateException( "attempted to delete an object of immutable class: " + MessageHelper.InfoString(persister) ); + } if ( log.IsDebugEnabled ) log.Debug( "deleting " + MessageHelper.InfoString(persister, entry.Id) ); *************** *** 1185,1189 **** { //ie the object came in from Update() ! entry.DeletedState = persister.GetPropertyValues(theObj); } else --- 1189,1193 ---- { //ie the object came in from Update() ! entry.DeletedState = persister.GetPropertyValues(obj); } else *************** *** 1193,1212 **** } ! interceptor.OnDelete(theObj, entry.Id, entry.DeletedState, persister.PropertyNames, propTypes); ! NullifyTransientReferences(entry.DeletedState, propTypes, false, theObj); ! ArrayList oldNullifiables = null; ArrayList oldDeletions = null; if ( persister.HasCascades ) { ! oldNullifiables = new ArrayList(); ! oldNullifiables.AddRange(nullifiables); oldDeletions = (ArrayList) deletions.Clone(); } ! nullifiables.Add( new Key(entry.Id, persister) ); entry.Status = Status.Deleted; // before any callbacks, etc, so subdeletions see that this deletion happend first ! ScheduledDeletion delete = new ScheduledDeletion(entry.Id, version, theObj, persister, this); deletions.Add(delete); // ensures that containing deletions happen before sub-deletions --- 1197,1216 ---- } ! interceptor.OnDelete(obj, entry.Id, entry.DeletedState, persister.PropertyNames, propTypes); ! NullifyTransientReferences(entry.DeletedState, propTypes, false, obj); ! // in h2.0.3 this is a Set ! IDictionary oldNullifiables = null; ArrayList oldDeletions = null; if ( persister.HasCascades ) { ! oldNullifiables = new Hashtable(nullifiables); oldDeletions = (ArrayList) deletions.Clone(); } ! nullifiables[ new Key(entry.Id, persister) ] = new object(); entry.Status = Status.Deleted; // before any callbacks, etc, so subdeletions see that this deletion happend first ! ScheduledDeletion delete = new ScheduledDeletion(entry.Id, version, obj, persister, this); deletions.Add(delete); // ensures that containing deletions happen before sub-deletions *************** *** 1215,1220 **** // after nullify, because we don't want to nullify references to subdeletions // try to do callback + cascade ! if ( persister.ImplementsLifecycle ) { ! if ( ( (ILifecycle)theObj).OnDelete(this) == LifecycleVeto.Veto ) { //rollback deletion RollbackDeletion(entry, delete); --- 1219,1226 ---- // after nullify, because we don't want to nullify references to subdeletions // try to do callback + cascade ! if ( persister.ImplementsLifecycle ) ! { ! if ( ( (ILifecycle)obj).OnDelete(this) == LifecycleVeto.Veto ) ! { //rollback deletion RollbackDeletion(entry, delete); *************** *** 1224,1232 **** //BEGIN YUCKINESS: ! if ( persister.HasCascades ) { ! int start = deletions.Count; ! IList newNullifiables = nullifiables; nullifiables = oldNullifiables; --- 1230,1238 ---- //BEGIN YUCKINESS: ! if ( persister.HasCascades ) ! { int start = deletions.Count; ! IDictionary newNullifiables = nullifiables; nullifiables = oldNullifiables; *************** *** 1235,1246 **** { // cascade-delete to collections "BEFORE" the collection owner is deleted ! Cascades.Cascade(this, persister, theObj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeAfterInsertBeforeDelete); } finally { cascading--; ! foreach(object oldNullify in oldNullifiables) { ! newNullifiables.Add(oldNullify); } nullifiables = newNullifiables; --- 1241,1252 ---- { // cascade-delete to collections "BEFORE" the collection owner is deleted ! Cascades.Cascade(this, persister, obj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeAfterInsertBeforeDelete); } finally { cascading--; ! foreach(DictionaryEntry oldNullifyDictEntry in oldNullifiables) { ! newNullifiables[oldNullifyDictEntry.Key] = oldNullifyDictEntry.Value; } nullifiables = newNullifiables; *************** *** 1271,1275 **** // cascade-save to many-to-one AFTER the parent was saved ! Cascades.Cascade(this, persister, theObj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeBeforeInsertAfterDelete); } catch (Exception e) --- 1277,1281 ---- // cascade-save to many-to-one AFTER the parent was saved ! Cascades.Cascade(this, persister, obj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeBeforeInsertAfterDelete); } catch (Exception e) *************** *** 1303,1311 **** { if ( log.IsDebugEnabled ) log.Debug( "collection dereferenced while transient " + MessageHelper.InfoString(role, id) ); ! //TODO: H2.0.3 - add back in when CollectionPersister.HasOrphanDelete is coded ! // if(role.HasOrphanDelete) ! // { ! // throw new HibernateException("You may not dereference a collection with cascade=\"all-delete-orphan\""); ! // } collectionRemovals.Add( new ScheduledCollectionRemove(role, id, false, this) ); } --- 1309,1316 ---- { if ( log.IsDebugEnabled ) log.Debug( "collection dereferenced while transient " + MessageHelper.InfoString(role, id) ); ! if(role.HasOrphanDelete) ! { ! throw new HibernateException("You may not dereference a collection with cascade=\"all-delete-orphan\""); ! } collectionRemovals.Add( new ScheduledCollectionRemove(role, id, false, this) ); } |