public void BatchingTopologicalSort_throws_with_formatted_message_when_cycle_cannot_be_broken() { const string message = "Formatted cycle"; var vertexOne = new Vertex { Id = 1 }; var vertexTwo = new Vertex { Id = 2 }; var vertexThree = new Vertex { Id = 3 }; var edgeOne = new Edge { Id = 1 }; var edgeTwo = new Edge { Id = 2 }; var edgeThree = new Edge { Id = 3 }; var graph = new Multigraph <Vertex, Edge>(); graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree }); // 1 -> {2} graph.AddEdge(vertexOne, vertexTwo, edgeOne); // 2 -> {3} graph.AddEdge(vertexTwo, vertexThree, edgeTwo); // 3 -> {1} graph.AddEdge(vertexThree, vertexOne, edgeThree); Dictionary <Vertex, Tuple <Vertex, Vertex, IEnumerable <Edge> > > cycleData = null; Func <IEnumerable <Tuple <Vertex, Vertex, IEnumerable <Edge> > >, string> formatter = data => { cycleData = data.ToDictionary(entry => entry.Item1); return(message); }; Assert.Equal( Strings.CircularDependency(message), Assert.Throws <InvalidOperationException>(() => graph.BatchingTopologicalSort(formatter)).Message); Assert.Equal(3, cycleData.Count()); Assert.Equal(vertexTwo, cycleData[vertexOne].Item2); Assert.Equal(new[] { edgeOne }, cycleData[vertexOne].Item3); Assert.Equal(vertexThree, cycleData[vertexTwo].Item2); Assert.Equal(new[] { edgeTwo }, cycleData[vertexTwo].Item3); Assert.Equal(vertexOne, cycleData[vertexThree].Item2); Assert.Equal(new[] { edgeThree }, cycleData[vertexThree].Item3); }
private static IEnumerable <IEntityType> Sort(IEnumerable <IEntityType> entityTypes) { var entityTypeGraph = new Multigraph <IEntityType, int>(); entityTypeGraph.AddVertices(entityTypes); foreach (var entityType in entityTypes.Where(et => et.BaseType != null)) { entityTypeGraph.AddEdge(entityType.BaseType !, entityType, 0); } return(entityTypeGraph.BatchingTopologicalSort().SelectMany(b => b.OrderBy(et => et.Name))); }
// To avoid violating store constraints the modification commands must be sorted // according to these rules: // // 1. Commands adding rows or modifying the candidate key values (when supported) must precede // commands adding or modifying rows that will be referencing the former // 2. Commands deleting rows or modifying the foreign key values must precede // commands deleting rows or modifying the candidate key values (when supported) of rows // that are currently being referenced by the former // 3. Commands deleting rows or modifying the foreign key values must precede // commands adding or modifying the foreign key values to the same values // if foreign key is unique /// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected virtual IReadOnlyList <List <ModificationCommand> > TopologicalSort([NotNull] IEnumerable <ModificationCommand> commands) { var modificationCommandGraph = new Multigraph <ModificationCommand, IAnnotatable>(); modificationCommandGraph.AddVertices(commands); // The predecessors map allows to populate the graph in linear time var predecessorsMap = CreateKeyValuePredecessorMap(modificationCommandGraph); AddForeignKeyEdges(modificationCommandGraph, predecessorsMap); AddUniqueValueEdges(modificationCommandGraph); return(modificationCommandGraph.BatchingTopologicalSort(FormatCycle)); }
// To avoid violating store constraints the modification commands must be sorted // according to these rules: // // 1. Commands adding rows or modifying the candidate key values (when supported) must precede // commands adding or modifying rows that will be referencing the former // 2. Commands deleting rows or modifying the foreign key values must precede // commands deleting rows or modifying the candidate key values (when supported) of rows // that are currently being referenced by the former // 3. Commands deleting rows or modifying the foreign key values must precede // commands adding or modifying the foreign key values to the same values // if foreign key is unique protected virtual IReadOnlyList <List <ModificationCommand> > TopologicalSort([NotNull] IEnumerable <ModificationCommand> commands) { var modificationCommandGraph = new Multigraph <ModificationCommand, IForeignKey>(); modificationCommandGraph.AddVertices(commands); // The predecessors map allows to populate the graph in linear time var predecessorsMap = CreateKeyValuePredecessorMap(modificationCommandGraph); AddForeignKeyEdges(modificationCommandGraph, predecessorsMap); var sortedCommands = modificationCommandGraph.BatchingTopologicalSort(data => { return(string.Join(", ", data.Select(d => d.Item3.First()))); }); return(sortedCommands); }
// To avoid violating store constraints the modification commands must be sorted // according to these rules: // // 1. Commands adding rows or modifying the candidate key values (when supported) must precede // commands adding or modifying rows that will be referencing the former // 2. Commands deleting rows or modifying the foreign key values must precede // commands deleting rows or modifying the candidate key values (when supported) of rows // that are currently being referenced by the former // 3. Commands deleting rows or modifying the foreign key values must precede // commands adding or modifying the foreign key values to the same values // if foreign key is unique /// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected virtual IReadOnlyList<List<ModificationCommand>> TopologicalSort([NotNull] IEnumerable<ModificationCommand> commands) { var modificationCommandGraph = new Multigraph<ModificationCommand, IForeignKey>(); modificationCommandGraph.AddVertices(commands); // The predecessors map allows to populate the graph in linear time var predecessorsMap = CreateKeyValuePredecessorMap(modificationCommandGraph); AddForeignKeyEdges(modificationCommandGraph, predecessorsMap); var sortedCommands = modificationCommandGraph.BatchingTopologicalSort(data => { return string.Join(", ", data.Select(d => d.Item3.First())); }); return sortedCommands; }