/// <summary> Delete any entities that were removed from the collection</summary> private void DeleteOrphans(string entityName, IPersistentCollection pc) { //TODO: suck this logic into the collection! ICollection orphans; if (pc.WasInitialized) { CollectionEntry ce = eventSource.PersistenceContext.GetCollectionEntry(pc); orphans = ce == null ? CollectionHelper.EmptyCollection : ce.GetOrphans(entityName, pc); } else { orphans = pc.GetQueuedOrphans(entityName); } foreach (object orphan in orphans) { if (orphan != null) { log.Info("deleting orphaned entity instance: " + entityName); eventSource.Delete(entityName, orphan, false, null); } } }
public override void Cascade(IEventSource session, object child, string entityName, object anything, bool isCascadeDeleteEnabled) { if (log.IsDebugEnabled()) { log.Debug("cascading to delete: {0}", entityName); } session.Delete(entityName, child, isCascadeDeleteEnabled, (ISet <object>)anything); }
public override void Cascade(IEventSource session, object child, string entityName, object anything, bool isCascadeDeleteEnabled) { if (log.IsDebugEnabled) { log.Debug("cascading to delete: " + entityName); } session.Delete(entityName, child, isCascadeDeleteEnabled, (ISet)anything); }
/// <summary> Cascade an action to the child or children</summary> private void CascadeProperty(object parent, object child, IType type, CascadeStyle style, string propertyName, object anything, bool isCascadeDeleteEnabled) { if (child != null) { if (type.IsAssociationType) { IAssociationType associationType = (IAssociationType)type; if (CascadeAssociationNow(associationType)) { CascadeAssociation(parent, child, type, style, anything, isCascadeDeleteEnabled); } } else if (type.IsComponentType) { CascadeComponent(parent, child, (IAbstractComponentType)type, propertyName, anything); } } else { // potentially we need to handle orphan deletes for one-to-ones here... if (type.IsEntityType && ((EntityType)type).IsLogicalOneToOne()) { // We have a physical or logical one-to-one and from previous checks we know we // have a null value. See if the attribute cascade settings and action-type require // orphan checking if (style.HasOrphanDelete && action.DeleteOrphans) { // value is orphaned if loaded state for this property shows not null // because it is currently null. EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent); if (entry != null && entry.Status != Status.Saving) { object loadedValue; if (componentPathStack.Count == 0) { // association defined on entity loadedValue = entry.GetLoadedValue(propertyName); // Check this is not a null carrying proxy. The no-proxy load is currently handled by // putting a proxy (!) flagged for unwrapping (even for non-constrained one-to-one, // which association may be null) in the loadedState of the parent. The unwrap flag // causes it to support having a null implementation, instead of throwing an entity // not found error. loadedValue = eventSource.PersistenceContext.UnproxyAndReassociate(loadedValue); } else { // association defined on component // todo : this is currently unsupported because of the fact that // we do not know the loaded state of this value properly // and doing so would be very difficult given how components and // entities are loaded (and how 'loaded state' is put into the // EntityEntry). Solutions here are to either: // 1) properly account for components as a 2-phase load construct // 2) just assume the association was just now orphaned and // issue the orphan delete. This would require a special // set of SQL statements though since we do not know the // orphaned value, something a delete with a subquery to // match the owner. loadedValue = null; } if (loadedValue != null) { eventSource.Delete(entry.Persister.EntityName, loadedValue, false, null); } } } } } }