Example #1
0
        /// <summary>
        /// Traverses the nodes in a <see cref="NodeLayer"/>.
        /// </summary>
        private void Traverse(NodeLayer currentLayer, ResourceHook target, Action <IResourceHookContainer, INode> action)
        {
            if (!currentLayer.AnyEntities())
            {
                return;
            }
            foreach (INode node in currentLayer)
            {
                var entityType    = node.ResourceType;
                var hookContainer = _executorHelper.GetResourceHookContainer(entityType, target);
                if (hookContainer == null)
                {
                    continue;
                }
                action(hookContainer, node);
            }

            Traverse(_traversalHelper.CreateNextLayer(currentLayer.ToList()), target, action);
        }
Example #2
0
        /// <summary>
        /// Fires the nested before hooks for entities in the current <paramref name="layer"/>
        /// </summary>
        /// <remarks>
        /// For example: consider the case when the owner of article1 (one-to-one)
        /// is being updated from owner_old to owner_new, where owner_new is currently already
        /// related to article2. Then, the following nested hooks need to be fired in the following order.
        /// First the BeforeUpdateRelationship should be for owner1, then the
        /// BeforeImplicitUpdateRelationship hook should be fired for
        /// owner2, and lastly the BeforeImplicitUpdateRelationship for article2.</remarks>
        private void FireNestedBeforeUpdateHooks(ResourcePipeline pipeline, NodeLayer layer)
        {
            foreach (INode node in layer)
            {
                var         nestedHookContainer = _executorHelper.GetResourceHookContainer(node.ResourceType, ResourceHook.BeforeUpdateRelationship);
                IEnumerable uniqueEntities      = node.UniqueEntities;
                RightType   entityType          = node.ResourceType;
                Dictionary <RelationshipAttribute, IEnumerable> currentEntitiesGrouped;
                Dictionary <RelationshipAttribute, IEnumerable> currentEntitiesGroupedInverse;

                // fire the BeforeUpdateRelationship hook for owner_new
                if (nestedHookContainer != null)
                {
                    if (uniqueEntities.Cast <IIdentifiable>().Any())
                    {
                        var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray();
                        var dbValues      = LoadDbValues(entityType, uniqueEntities, ResourceHook.BeforeUpdateRelationship, relationships);

                        // these are the entities of the current node grouped by
                        // RelationshipAttributes that occured in the previous layer
                        // so it looks like { HasOneAttribute:owner  =>  owner_new }.
                        // Note that in the BeforeUpdateRelationship hook of Person,
                        // we want want inverse relationship attribute:
                        // we now have the one pointing from article -> person, ]
                        // but we require the the one that points from person -> article
                        currentEntitiesGrouped        = node.RelationshipsFromPreviousLayer.GetRightEntities();
                        currentEntitiesGroupedInverse = ReplaceKeysWithInverseRelationships(currentEntitiesGrouped);

                        var resourcesByRelationship = CreateRelationshipHelper(entityType, currentEntitiesGroupedInverse, dbValues);
                        var allowedIds = CallHook(nestedHookContainer, ResourceHook.BeforeUpdateRelationship, new object[] { GetIds(uniqueEntities), resourcesByRelationship, pipeline }).Cast <string>();
                        var updated    = GetAllowedEntities(uniqueEntities, allowedIds);
                        node.UpdateUnique(updated);
                        node.Reassign();
                    }
                }

                // Fire the BeforeImplicitUpdateRelationship hook for owner_old.
                // Note: if the pipeline is Post it means we just created article1,
                // which means we are sure that it isn't related to any other entities yet.
                if (pipeline != ResourcePipeline.Post)
                {
                    // To fire a hook for owner_old, we need to first get a reference to it.
                    // For this, we need to query the database for the  HasOneAttribute:owner
                    // relationship of article1, which is referred to as the
                    // left side of the HasOneAttribute:owner relationship.
                    var leftEntities = node.RelationshipsFromPreviousLayer.GetLeftEntities();
                    if (leftEntities.Any())
                    {
                        // owner_old is loaded, which is an "implicitly affected entity"
                        FireForAffectedImplicits(entityType, leftEntities, pipeline, uniqueEntities);
                    }
                }

                // Fire the BeforeImplicitUpdateRelationship hook for article2
                // For this, we need to query the database for the current owner
                // relationship value of owner_new.
                currentEntitiesGrouped = node.RelationshipsFromPreviousLayer.GetRightEntities();
                if (currentEntitiesGrouped.Any())
                {
                    // rightEntities is grouped by relationships from previous
                    // layer, ie { HasOneAttribute:owner  =>  owner_new }. But
                    // to load article2 onto owner_new, we need to have the
                    // RelationshipAttribute from owner to article, which is the
                    // inverse of HasOneAttribute:owner
                    currentEntitiesGroupedInverse = ReplaceKeysWithInverseRelationships(currentEntitiesGrouped);
                    // Note that currently in the JADNC implementation of hooks,
                    // the root layer is ALWAYS homogenous, so we safely assume
                    // that for every relationship to the previous layer, the
                    // left type is the same.
                    LeftType leftType = currentEntitiesGrouped.First().Key.LeftType;
                    FireForAffectedImplicits(leftType, currentEntitiesGroupedInverse, pipeline);
                }
            }
        }