/// <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); }
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); }