public void AddVertices_adds_vertices() { var model = new Model(); var entityTypeA = model.AddEntityType(typeof(A)); var entityTypeB = model.AddEntityType(typeof(B)); var graph = new BidirectionalAdjacencyListGraph <EntityType>(); graph.AddVertices(new[] { entityTypeA, entityTypeB }); Assert.Equal(new[] { entityTypeA, entityTypeB }, graph.Vertices); }
// 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 modifying or adding 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 protected virtual IEnumerable <List <ModificationCommand> > TopologicalSort([NotNull] IEnumerable <ModificationCommand> commands) { Check.NotNull(commands, "commands"); var modificationCommandGraph = new BidirectionalAdjacencyListGraph <ModificationCommand>(); modificationCommandGraph.AddVertices(commands); // The predecessors map allows to populate the graph in linear time var predecessorsMap = CreateKeyValuePredecessorMap(modificationCommandGraph); AddForeignKeyEdges(modificationCommandGraph, predecessorsMap); return(modificationCommandGraph.TopologicalSort()); }
public void AddEdge_adds_edge() { var model = new Model(); var entityTypeA = model.AddEntityType(typeof(A)); var entityTypeB = model.AddEntityType(typeof(B)); var entityTypeC = model.AddEntityType(typeof(C)); var graph = new BidirectionalAdjacencyListGraph <EntityType>(); graph.AddVertex(entityTypeA); graph.AddVertex(entityTypeB); graph.AddVertex(entityTypeC); graph.AddEdge(entityTypeA, entityTypeB); graph.AddEdge(entityTypeA, entityTypeC); graph.AddEdge(entityTypeB, entityTypeC); Assert.Equal(new[] { entityTypeB, entityTypeC }, graph.GetOutgoingNeighbours(entityTypeA)); Assert.Equal(new[] { entityTypeA, entityTypeB }, graph.GetIncomingNeighbours(entityTypeC)); }
private void AddForeignKeyEdges( BidirectionalAdjacencyListGraph <ModificationCommand> commandGraph, Dictionary <KeyValue, List <ModificationCommand> > predecessorsMap) { foreach (var command in commandGraph.Vertices) { if (command.EntityState == EntityState.Modified || command.EntityState == EntityState.Added) { foreach (var stateEntry in command.StateEntries) { foreach (var foreignKey in stateEntry.EntityType.ForeignKeys) { var dependentKeyValue = CreateDependentKeyValue(stateEntry, foreignKey, ValueType.Current); if (dependentKeyValue.Key != EntityKey.NullEntityKey) { List <ModificationCommand> predecessorCommands; if (predecessorsMap.TryGetValue(dependentKeyValue, out predecessorCommands)) { foreach (var predecessor in predecessorCommands) { if (predecessor != command) { commandGraph.AddEdge(predecessor, command); } } } } } } } // TODO: also examine modified entities here when principal key modification is supported if (command.EntityState == EntityState.Deleted) { foreach (var stateEntry in command.StateEntries) { foreach (var foreignKey in stateEntry.EntityType.GetReferencingForeignKeys()) { var principalKeyValue = CreatePrincipalKeyValue(stateEntry.OriginalValues, foreignKey, ValueType.Original); if (principalKeyValue.Key != EntityKey.NullEntityKey) { List <ModificationCommand> predecessorCommands; if (predecessorsMap.TryGetValue(principalKeyValue, out predecessorCommands)) { foreach (var predecessor in predecessorCommands) { if (predecessor != command) { commandGraph.AddEdge(predecessor, command); } } } } } } } } }