private void Ripple(TEntity instance, DataProviderDeleteSettings settings, Parameters parameters)
        {
            // Ripple each instance precisely once per DeleteStack traversal
            // (Note that this includes subtypes instances - i.e. the entire hierarchy is rippled from root call to RippleDelete)
            if (!DeleteStack.HasBeenRippledDuringCurrentTraversal(instance))
            {
                if (!DeleteStack.IsResolved(instance))
                {
                    // Remember we've seen this instance
                    DeleteStack.AddSeenObject(instance);

                    // Count blockers before and after rippling in order to determine if instance can be added to the resolved list
                    int numBlockers = DeleteStack.BlockersDuringCurrentTraversal.Count();

                    // Call virtual Ripple
                    RippleDelete(instance, parameters, settings);

                    // no errors => Can delete this object => Add to the resolved list
                    if (numBlockers == DeleteStack.BlockersDuringCurrentTraversal.Count() &&
                        !DeleteStack.HasUnresolvedDependencies(instance))
                    {
                        DeleteStack.MarkResolved(instance);

                        // Do any deferred deletes
                        DoDeferredDeletes(parameters, settings);
                    }
                }
            }
        }
 private void CheckResolved(IDataObject instanceBeingDeleted, IDataObject dependency)
 {
     if (!DeleteStack.IsResolved(dependency))
     {
         AddBlockage("Unresolved dependency", instanceBeingDeleted, dependency);
         DeleteStack.AddUnresolvedDependency(instanceBeingDeleted, dependency);
     }
 }
 protected void Delete <T>(T item, Parameters parameters, DataProviderDeleteSettings settings, TEntity currentInstance) where T : IDataObject
 {
     if (!DeleteStack.IsResolved(item))
     {
         var db = ApplicationSettings.Container.Resolve <IDataProvider <T> >();
         db.Delete(item, settings.SecurityFilterExpression, settings.Context, parameters, settings.SkipSecurity);
         CheckResolved(currentInstance, item);
         NeedResync = true;
     }
 }
 protected void ReverseCascade(IDataObject item)
 {
     if (item != null)
     {
         // If item hasn't yet been seen during the current delete traversal, then defer-delete it in order that we (many side instances) are marked resolved *before* (one-side) item.
         if (!DeleteStack.HasBeenRippledDuringCurrentTraversal(item))
         {
             AddDeferredDeleteItem(item);
         }
     }
 }
        protected bool AddAnyBlockages <T>(string reason, TEntity instance, IEnumerable <T> dependencies) where T : IDataObject
        {
            bool blocked = false;

            foreach (var item in dependencies)
            {
                if (!DeleteStack.IsResolved(item))
                {
                    blocked = true;
                    AddBlockage(reason, instance, item);
                }
            }

            return(blocked);
        }
        protected void Save(TEntity instance)
        {
            if (DeleteStack.IsResolved(instance))
            {
                return;
            }

            var db = ApplicationSettings.Container.Resolve <IDataProvider <TEntity> >() as IDataProvider2 <TEntity>;

            if (db != null)
            {
                db.Save(instance, new DataProviderSaveSettings {
                    DeepDataMapping = false, Transaction = this.Transaction, SkipSecurity = true
                });
                NeedResync = true;
            }
        }
        protected void Save(IDataObject obj)
        {
            if (DeleteStack.IsResolved(obj))
            {
                return;
            }

            dynamic db = ApplicationSettings.Container.Resolve <IEntityDataProvider>().GetDataProviderForEntity(obj) as IDataProvider2;

            if (db != null)
            {
                // Save a flat clone to ensure no relations explored during the save
                db.Save(obj.Clone(recursive: false), new DataProviderSaveSettings {
                    DeepDataMapping = false, Transaction = this.Transaction, SkipSecurity = true
                });
                NeedResync = true;
            }
        }
        protected void AddBlockage(string reason, IDataObject blocked, IDataObject blocker)
        {
            if (DeleteStack.IsResolved(blocker))
            {
                return;
            }

            var blockage = new DeleteBlockage
            {
                Reason     = reason,
                Blocked    = blocked,
                Blocker    = blocker,
                DeleteRoot = DeleteStack.RootObject,
                Parameters = this.Parameters
            };

            DeleteStack.BlockersDuringCurrentTraversal.Add(blockage);
            DeleteStack.AddUnresolvedDependency(blocked, blocker);

            // Trace
            var explain = ApplicationSettings.Container.Resolve <IDeleteBlockageExplanationProvider>();

            DeleteStack.Trace("BLOCKER: " + explain.Explain(blockage));
        }