/// <summary>
        /// Move descendant elements with parent node specified as 'from' to new parent node, specified as 'to'.
        /// </summary>
        /// <typeparam name="T">Type of elements. Should implement IHasTreeEntry interface. </typeparam>
        /// <param name="collection">Collection containing hierarchical data. </param>
        /// <param name="from">Parent node from where to move descendants. </param>
        /// <param name="to">Node to move descendants into. </param>
        /// <returns>List of TreeEntry items with recalculated positions. </returns>
        public static IEnumerable <TreeEntry> MoveSubtree <T>(this DbSet <T> collection, T from, T to)
            where T : class, IHasTreeEntry
        {
            var sourceInterval = collection.EnsureTreeEntryLoaded(from);
            var targetInterval = collection.EnsureTreeEntryLoaded(to);

            var relocation =
                NestedIntervalMath.BuildSubtreeRelocationMatrix(sourceInterval, targetInterval, 1);

            var depthDiff = targetInterval.Depth - sourceInterval.Depth;

            var elementsToUpdate = collection.Include(i => i.TreeEntry)
                                   .DescendantsOf(from)
                                   .ToList();

            var intervalsToUpdate = elementsToUpdate
                                    .Select(i => i.TreeEntry)
                                    .ToList();

            foreach (var item in elementsToUpdate)
            {
                item.TreeEntry.SetFromInterval(NestedIntervalMath.MultiplyMatrixToInterval(relocation, item.TreeEntry));
                item.TreeEntry.Depth += depthDiff;
            }

            collection.UpdateRange(elementsToUpdate);

            return(intervalsToUpdate);
        }
示例#2
0
        public void RelocatedTreeHasSameValuesAsCreated()
        {
            var firstRoot       = NestedIntervalMath.GetIntervalByPosition(1);
            var firstChild      = NestedIntervalMath.GetIntervalByPosition(firstRoot, 2);
            var firstChildChild = NestedIntervalMath.GetIntervalByPosition(firstChild, 1);

            var secondRoot       = NestedIntervalMath.GetIntervalByPosition(2);
            var secondChild      = NestedIntervalMath.GetIntervalByPosition(secondRoot, 5);       // < - should be same as relocated firstroot
            var secondchildchild = NestedIntervalMath.GetIntervalByPosition(secondChild, 2);      // < - should be same as relocated firstchild
            var second3child     = NestedIntervalMath.GetIntervalByPosition(secondchildchild, 1); // < - should be same as relocated firstchildchild

            var relocationMatrix   = NestedIntervalMath.BuildSubtreeRelocationMatrix(firstRoot, secondRoot, 5);
            var firstRootRelocated =
                NestedIntervalMath.MultiplyMatrixToInterval(relocationMatrix, firstRoot);
            var firstChildRelocated = NestedIntervalMath.MultiplyMatrixToInterval(relocationMatrix, firstChild);

            var firstChildChildRelocated =
                NestedIntervalMath.MultiplyMatrixToInterval(relocationMatrix, firstChildChild);

            firstRootRelocated.Depth       = 2; // Just set depth for equality test. it's not computed in math multiplication
            firstChildRelocated.Depth      = 3;
            firstChildChildRelocated.Depth = 4;
            Assert.AreEqual(secondChild, firstRootRelocated);
            Assert.AreEqual(secondchildchild, firstChildRelocated);
            Assert.AreEqual(second3child, firstChildChildRelocated);
        }