Example #1
0
        public Graphlet1(string name, IEnumerable<int> includedChannels, Multigraph mg)
        {
            InitializeComponent();

            this.mg = mg;
            this.DataContext = mg;
            this.gp = mg.gp;
            this.name.Content = name;
            this.Height = MainWindow.graphletSize;
            this.Width = this.Height * mg.aspect;
            StringBuilder tooltip = new StringBuilder(includedChannels.Count() > 1 ? name : "");
            bool colon = true;
            foreach (int chan in includedChannels)
            {
                if (includedChannels.Count() > 1)
                    tooltip.Append((colon ? ": " : ", "));
                tooltip.Append(Multigraph.trimChannelName(mg.fis.ChannelNames(chan)) + "(" + (chan + 1).ToString("0") + ")");
                colon = false;
                this.channels.Add(chan);
            }
            this.graphletName.Text = tooltip.ToString();
            if (mg.typeAxis == AxisType.Pos)
                offset = MainWindow._baseSize;
            else if (mg.typeAxis == AxisType.PosNeg)
            {
                offset = MainWindow._baseSize / 2D;
                Canvas.SetBottom(xAxis, offset);
            }
            else
            {
                offset = 0D;
                Canvas.SetBottom(xAxis, MainWindow._baseSize);
            }
        }
 private IReadOnlyList<IEntityType> Sort(IReadOnlyList<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.TopologicalSort();
 }
 public NavigationControl(Multigraph m)
 {
     mg = m;
     InitializeComponent();
     DataContext = mg;
     this.LocateChannel.Items.Add("None"); //Initialize channel locator list
     foreach (Multigraph.displayChannel dc in mg.displayedChannels)
         this.LocateChannel.Items.Add(Multigraph.trimChannelName(mg.fis.ChannelNames(dc.channel)));
     this.LocateChannel.SelectedIndex = 0;
     this.specScale.Text = mg.useAllYMax ? "Scale Y to all chans" : mg.fixedYMax ? "Scale Y to " + mg.fixedYMaxValue.ToString() : "Scale Y to each chan";
     this.specTransform.Text = "Point transform = " + mg.pt.Method.Name;
     this.specPosition.Text = mg.usePositionData ? "Using position data" : "Default locations for all";
 }
Example #4
0
        public SinglePlot(Graphlet1 graph, Multigraph t)
        {
            InitializeComponent();

            g = graph;
            mg = t;
            loc.DataContext = this;
            tabName.Text = g.mg.FMFileName + ": " + (string)g.name.Content;
            localXScale = (double)mg._decimation * mg.finalXScale / g.graphletXScale; //doesn't change; Y-scale may
            this.Cursor = Cursors.Cross;
            Info.DataContext = g;
            plot.Width = MainWindow.graphletSize * g.mg.aspect + 12;
            plot.Height = MainWindow.graphletSize + 12;
            plot.Children.Add(g);
            Canvas.SetBottom(g, 6D);
            Canvas.SetLeft(g, 6D);
        }
Example #5
0
        public void TopologicalSort_throws_with_default_message_when_cycle_cannot_be_broken()
        {
            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);

            Assert.Equal(
                CoreStrings.CircularDependency(string.Join(" -> ", new[] { vertexOne, vertexTwo, vertexThree, vertexOne }.Select(v => v.ToString()))),
                Assert.Throws <InvalidOperationException>(() => graph.TopologicalSort()).Message);
        }
Example #6
0
        public void TopologicalSort_on_tree_graph_returns_all_verticies_in_order()
        {
            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, 3}
            graph.AddEdge(vertexOne, vertexTwo, edgeOne);
            graph.AddEdge(vertexOne, vertexThree, edgeTwo);
            // 3 -> {2}
            graph.AddEdge(vertexThree, vertexTwo, edgeThree);

            Assert.Equal(
                new[] { vertexOne, vertexThree, vertexTwo },
                graph.TopologicalSort().ToArray());
        }
Example #7
0
        public void TopologicalSort_on_self_ref_can_break_cycle()
        {
            var vertexOne = new Vertex {
                Id = 1
            };

            var edgeOne = new Edge {
                Id = 1
            };

            var graph = new Multigraph <Vertex, Edge>();

            graph.AddVertex(vertexOne);

            // 1 -> {1}
            graph.AddEdge(vertexOne, vertexOne, edgeOne);

            Assert.Equal(
                new[] { vertexOne },
                graph.TopologicalSort((from, to, edges) =>
                                      from == vertexOne &&
                                      to == vertexOne &&
                                      edges.Intersect(new[] { edgeOne }).Count() == 1).ToArray());
        }
        private void AddForeignKeyEdges(
            Multigraph <ModificationCommand, IAnnotatable> commandGraph,
            Dictionary <IKeyValueIndex, List <ModificationCommand> > predecessorsMap)
        {
            foreach (var command in commandGraph.Vertices)
            {
                switch (command.EntityState)
                {
                case EntityState.Modified:
                case EntityState.Added:
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                    {
                        var entry = command.Entries[entryIndex];
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints();

                            var foreignKeyValueColumnModifications = command.ColumnModifications.Where(
                                cm => (cm.IsWrite || cm.IsRead) && foreignKey.Properties.Contains(cm.Property));

                            if (!constraints.Any() ||
                                (command.EntityState == EntityState.Modified &&
                                 !foreignKeyValueColumnModifications.Any()))
                            {
                                continue;
                            }

                            var dependentKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreateDependentKeyValue((InternalEntityEntry)entry, foreignKey);
                            if (dependentKeyValue == null)
                            {
                                continue;
                            }

                            AddMatchingPredecessorEdge(
                                predecessorsMap, dependentKeyValue, commandGraph, command, foreignKey);
                        }
                    }

                    break;

                case EntityState.Deleted:
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                    {
                        var entry = command.Entries[entryIndex];
                        foreach (var foreignKey in entry.EntityType.GetReferencingForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints()
                                              .Where(c => c.PrincipalTable.Name == command.TableName && c.PrincipalTable.Schema == command.Schema);
                            if (!constraints.Any())
                            {
                                continue;
                            }

                            var principalKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreatePrincipalKeyValueFromOriginalValues((InternalEntityEntry)entry, foreignKey);
                            if (principalKeyValue != null)
                            {
                                AddMatchingPredecessorEdge(
                                    predecessorsMap, principalKeyValue, commandGraph, command, foreignKey);
                            }
                        }
                    }

                    break;
                }
            }
        }
        // Builds a map from foreign key values to list of modification commands, with an entry for every command
        // that may need to precede some other command involving that foreign key value.
        private Dictionary <IKeyValueIndex, List <ModificationCommand> > CreateKeyValuePredecessorMap(
            Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            var predecessorsMap = new Dictionary <IKeyValueIndex, List <ModificationCommand> >();

            foreach (var command in commandGraph.Vertices)
            {
                var columnModifications = command.ColumnModifications;
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var i = 0; i < command.Entries.Count; i++)
                    {
                        var entry = command.Entries[i];
                        foreach (var foreignKey in entry.EntityType.GetReferencingForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints()
                                              .Where(c => c.PrincipalTable.Name == command.TableName && c.PrincipalTable.Schema == command.Schema);
                            var candidateKeyValueColumnModifications = columnModifications.Where(
                                cm => (cm.IsWrite || cm.IsRead) && foreignKey.PrincipalKey.Properties.Contains(cm.Property));

                            if (!constraints.Any() ||
                                (command.EntityState == EntityState.Modified &&
                                 !candidateKeyValueColumnModifications.Any()))
                            {
                                continue;
                            }

                            var principalKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreatePrincipalKeyValue((InternalEntityEntry)entry, foreignKey);

                            if (principalKeyValue != null)
                            {
                                if (!predecessorsMap.TryGetValue(principalKeyValue, out var predecessorCommands))
                                {
                                    predecessorCommands = new List <ModificationCommand>();
                                    predecessorsMap.Add(principalKeyValue, predecessorCommands);
                                }

                                predecessorCommands.Add(command);
                            }
                        }
                    }
                }

                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Deleted)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints();
                            var foreignKeyValueColumnModifications = columnModifications.Where(
                                cm => (cm.IsWrite || cm.IsRead) && foreignKey.Properties.Contains(cm.Property));

                            if (!constraints.Any() ||
                                (command.EntityState == EntityState.Modified &&
                                 !foreignKeyValueColumnModifications.Any()))
                            {
                                continue;
                            }

                            var dependentKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreateDependentKeyValueFromOriginalValues((InternalEntityEntry)entry, foreignKey);

                            if (dependentKeyValue != null)
                            {
                                if (!predecessorsMap.TryGetValue(dependentKeyValue, out var predecessorCommands))
                                {
                                    predecessorCommands = new List <ModificationCommand>();
                                    predecessorsMap.Add(dependentKeyValue, predecessorCommands);
                                }

                                predecessorCommands.Add(command);
                            }
                        }
                    }
                }
            }

            return(predecessorsMap);
        }
        /// <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 override IReadOnlyList <MigrationOperation> Sort([NotNull] IEnumerable <MigrationOperation> operations, [NotNull] MigrationsModelDiffer.DiffContext diffContext)
        {
            Check.NotNull(operations, nameof(operations));

            var dropForeignKeyOperations = new List <MigrationOperation>();
            var dropOperations           = new List <MigrationOperation>();
            var dropColumnOperations     = new List <MigrationOperation>();
            var dropTableOperations      = new List <DropTableOperation>();
            var ensureSchemaOperations   = new List <MigrationOperation>();
            var createSequenceOperations = new List <MigrationOperation>();
            var createTableOperations    = new List <CreateTableOperation>();
            var addColumnOperations      = new List <MigrationOperation>();
            var alterOperations          = new List <MigrationOperation>();
            var addForeignKeyOperations  = new List <MigrationOperation>();
            var renameColumnOperations   = new List <MigrationOperation>();
            var renameOperations         = new List <MigrationOperation>();
            var renameTableOperations    = new List <MigrationOperation>();
            var leftovers = new List <MigrationOperation>();

            foreach (var operation in operations)
            {
                var type = operation.GetType();
                if (type == typeof(DropForeignKeyOperation))
                {
                    dropForeignKeyOperations.Add(operation);
                }
                else if (_dropOperationTypes.Contains(type))
                {
                    dropOperations.Add(operation);
                }
                else if (type == typeof(DropColumnOperation))
                {
                    dropColumnOperations.Add(operation);
                }
                else if (type == typeof(DropTableOperation))
                {
                    dropTableOperations.Add((DropTableOperation)operation);
                }
                else if (type == typeof(EnsureSchemaOperation))
                {
                    ensureSchemaOperations.Add(operation);
                }
                else if (type == typeof(CreateSequenceOperation))
                {
                    createSequenceOperations.Add(operation);
                }
                else if (type == typeof(CreateTableOperation))
                {
                    createTableOperations.Add((CreateTableOperation)operation);
                }
                else if (type == typeof(AddColumnOperation))
                {
                    addColumnOperations.Add(operation);
                }
                else if (_alterOperationTypes.Contains(type))
                {
                    alterOperations.Add(operation);
                }
                else if (type == typeof(AddForeignKeyOperation))
                {
                    addForeignKeyOperations.Add(operation);
                }
                else if (type == typeof(RenameColumnOperation))
                {
                    renameColumnOperations.Add(operation);
                }
                else if (_renameOperationTypes.Contains(type))
                {
                    renameOperations.Add(operation);
                }
                else if (type == typeof(RenameTableOperation))
                {
                    renameTableOperations.Add(operation);
                }
                else
                {
                    Debug.Assert(false, "Unexpected operation type: " + operation.GetType());
                    leftovers.Add(operation);
                }
            }

            var createTableGraph = new Multigraph <CreateTableOperation, AddForeignKeyOperation>();

            createTableGraph.AddVertices(createTableOperations);
            foreach (var createTableOperation in createTableOperations)
            {
                foreach (var addForeignKeyOperation in createTableOperation.ForeignKeys)
                {
                    if ((addForeignKeyOperation.Table == addForeignKeyOperation.PrincipalTable) &&
                        (addForeignKeyOperation.Schema == addForeignKeyOperation.PrincipalSchema))
                    {
                        continue;
                    }

                    var principalCreateTableOperation = createTableOperations.FirstOrDefault(
                        o => (o.Name == addForeignKeyOperation.PrincipalTable) &&
                        (o.Schema == addForeignKeyOperation.PrincipalSchema));
                    if (principalCreateTableOperation != null)
                    {
                        createTableGraph.AddEdge(principalCreateTableOperation, createTableOperation, addForeignKeyOperation);
                    }
                }
            }
            createTableOperations = createTableGraph.TopologicalSort(
                (principalCreateTableOperation, createTableOperation, cyclicAddForeignKeyOperations) =>
            {
                foreach (var cyclicAddForeignKeyOperation in cyclicAddForeignKeyOperations)
                {
                    createTableOperation.ForeignKeys.Remove(cyclicAddForeignKeyOperation);
                    addForeignKeyOperations.Add(cyclicAddForeignKeyOperation);
                }

                return(true);
            }).ToList();

            var dropTableGraph = new Multigraph <DropTableOperation, IForeignKey>();

            dropTableGraph.AddVertices(dropTableOperations);
            foreach (var dropTableOperation in dropTableOperations)
            {
                var entityType = diffContext.GetMetadata(dropTableOperation);
                foreach (var foreignKey in (IEnumerable <IForeignKey>)GetForeignKeysInHierarchyMi.Invoke(this, new object[] { entityType }))
                {
                    var principalRootEntityType = foreignKey.PrincipalEntityType.RootType();
                    if (entityType == principalRootEntityType)
                    {
                        continue;
                    }

                    var principalDropTableOperation = diffContext.FindDrop(principalRootEntityType);
                    if (principalDropTableOperation != null)
                    {
                        dropTableGraph.AddEdge(dropTableOperation, principalDropTableOperation, foreignKey);
                    }
                }
            }
            var newDiffContext = new DiffContext();

            dropTableOperations = dropTableGraph.TopologicalSort(
                (dropTableOperation, principalDropTableOperation, foreignKeys) =>
            {
                dropForeignKeyOperations.AddRange(foreignKeys.SelectMany(c => Remove(c, newDiffContext)));

                return(true);
            }).ToList();

            var ret = dropForeignKeyOperations
                      .Concat(renameTableOperations)
                      .Concat(renameOperations)
                      .Concat(renameColumnOperations)
                      .Concat(dropOperations)
                      .Concat(dropColumnOperations)
                      .Concat(dropTableOperations)
                      .Concat(ensureSchemaOperations)
                      .Concat(createTableOperations)
                      .Concat(addColumnOperations)
                      .Concat(alterOperations)
                      .Concat(addForeignKeyOperations)
                      .Concat(leftovers)
                      .Concat(createSequenceOperations)
                      .ToArray();

            // Fixed #37 Renaming a table while adding a new field/column fails when updating the migration in the database.
            var rename = ret.Where(x => x is RenameTableOperation).ToList();

            foreach (RenameTableOperation rto in rename)
            {
                var fix = ret.Where(x => !(x is RenameTableOperation)).ToList();
                foreach (dynamic x in fix)
                {
                    try { x.Table = x.Table.Replace(rto.Name, rto.NewName); } catch { }
                }
            }

            // Fixed Renaming a table will drop and re-create PK issue.
            ret = ret.Where(x => !(x is AddPrimaryKeyOperation && ret.Any(y => y is DropPrimaryKeyOperation && ((DropPrimaryKeyOperation)y).Table == ((AddPrimaryKeyOperation)x).Table)) && !(x is DropPrimaryKeyOperation && ret.Any(y => y is AddPrimaryKeyOperation && ((AddPrimaryKeyOperation)y).Table == ((DropPrimaryKeyOperation)x).Table))).ToArray();

            return(ret);
        }
Example #11
0
        private void AddUniqueValueEdges(Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            Dictionary <IIndex, Dictionary <object[], ModificationCommand> >?indexPredecessorsMap = null;
            var keyPredecessorsMap = new Dictionary <(IKey, IKeyValueIndex), List <ModificationCommand> >();

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState != EntityState.Modified &&
                    command.EntityState != EntityState.Deleted)
                {
                    continue;
                }

                for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                {
                    var entry = command.Entries[entryIndex];
                    foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique && i.GetMappedTableIndexes().Any()))
                    {
                        if (entry.EntityState == EntityState.Modified &&
                            !index.Properties.Any(p => entry.IsModified(p)))
                        {
                            continue;
                        }

                        var valueFactory = index.GetNullableValueFactory <object[]>();
                        if (valueFactory.TryCreateFromOriginalValues(entry, out var indexValue))
                        {
                            indexPredecessorsMap ??= new Dictionary <IIndex, Dictionary <object[], ModificationCommand> >();
                            if (!indexPredecessorsMap.TryGetValue(index, out var predecessorCommands))
                            {
                                predecessorCommands = new Dictionary <object[], ModificationCommand>(valueFactory.EqualityComparer);
                                indexPredecessorsMap.Add(index, predecessorCommands);
                            }

                            if (!predecessorCommands.ContainsKey(indexValue))
                            {
                                predecessorCommands.Add(indexValue, command);
                            }
                        }
                    }

                    if (command.EntityState != EntityState.Deleted)
                    {
                        continue;
                    }

                    foreach (var key in entry.EntityType.GetKeys().Where(k => k.GetMappedConstraints().Any()))
                    {
                        var principalKeyValue = _keyValueIndexFactorySource
                                                .GetKeyValueIndexFactory(key)
                                                .CreatePrincipalKeyValue(entry, null);

                        if (principalKeyValue != null)
                        {
                            if (!keyPredecessorsMap.TryGetValue((key, principalKeyValue), out var predecessorCommands))
                            {
                                predecessorCommands = new List <ModificationCommand>();
                                keyPredecessorsMap.Add((key, principalKeyValue), predecessorCommands);
                            }

                            predecessorCommands.Add(command);
                        }
                    }
                }
            }

            if (indexPredecessorsMap != null)
            {
                foreach (var command in commandGraph.Vertices)
                {
                    if (command.EntityState == EntityState.Deleted)
                    {
                        continue;
                    }

                    foreach (var entry in command.Entries)
                    {
                        foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique && i.GetMappedTableIndexes().Any()))
                        {
                            if (entry.EntityState == EntityState.Modified &&
                                !index.Properties.Any(p => entry.IsModified(p)))
                            {
                                continue;
                            }

                            var valueFactory = index.GetNullableValueFactory <object[]>();
                            if (valueFactory.TryCreateFromCurrentValues(entry, out var indexValue) &&
                                indexPredecessorsMap.TryGetValue(index, out var predecessorCommands) &&
                                predecessorCommands.TryGetValue(indexValue, out var predecessor) &&
                                predecessor != command)
                            {
                                commandGraph.AddEdge(predecessor, command, index);
                            }
                        }
                    }
                }
            }

            if (keyPredecessorsMap != null)
            {
                foreach (var command in commandGraph.Vertices)
                {
                    if (command.EntityState != EntityState.Added)
                    {
                        continue;
                    }

                    foreach (var entry in command.Entries)
                    {
                        foreach (var key in entry.EntityType.GetKeys().Where(k => k.GetMappedConstraints().Any()))
                        {
                            var principalKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(key)
                                                    .CreatePrincipalKeyValue(entry, null);

                            if (principalKeyValue != null)
                            {
                                AddMatchingPredecessorEdge(
                                    keyPredecessorsMap, (key, principalKeyValue), commandGraph, command, key);
                            }
                        }
                    }
                }
            }
        }
Example #12
0
        private void AddUniqueValueEdges(Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            Dictionary <IIndex, Dictionary <object[], ModificationCommand> > predecessorsMap = null;

            foreach (var command in commandGraph.Vertices)
            {
                if (command.Predecessor != null)
                {
                    commandGraph.AddEdge(command.Predecessor, command, null);
                }

                if (command.EntityState != EntityState.Modified &&
                    command.EntityState != EntityState.Deleted)
                {
                    continue;
                }

                for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                {
                    var entry = command.Entries[entryIndex];
                    foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique && i.GetMappedTableIndexes().Any()))
                    {
                        if (command.EntityState == EntityState.Modified &&
                            !index.Properties.Any(p => entry.IsModified(p)))
                        {
                            continue;
                        }

                        var valueFactory = index.GetNullableValueFactory <object[]>();
                        if (valueFactory.TryCreateFromOriginalValues(entry, out var indexValue))
                        {
                            predecessorsMap ??= new Dictionary <IIndex, Dictionary <object[], ModificationCommand> >();
                            if (!predecessorsMap.TryGetValue(index, out var predecessorCommands))
                            {
                                predecessorCommands = new Dictionary <object[], ModificationCommand>(valueFactory.EqualityComparer);
                                predecessorsMap.Add(index, predecessorCommands);
                            }

                            if (!predecessorCommands.ContainsKey(indexValue))
                            {
                                predecessorCommands.Add(indexValue, command);
                            }
                        }
                    }
                }
            }

            if (predecessorsMap == null)
            {
                return;
            }

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique && i.GetMappedTableIndexes().Any()))
                        {
                            if (command.EntityState == EntityState.Modified &&
                                !index.Properties.Any(p => entry.IsModified(p)))
                            {
                                continue;
                            }

                            var valueFactory = index.GetNullableValueFactory <object[]>();
                            if (valueFactory.TryCreateFromCurrentValues(entry, out var indexValue) &&
                                predecessorsMap.TryGetValue(index, out var predecessorCommands) &&
                                predecessorCommands.TryGetValue(indexValue, out var predecessor) &&
                                predecessor != command)
                            {
                                commandGraph.AddEdge(predecessor, command, index);
                            }
                        }
                    }
                }
            }
        }
        // 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;
        }
        protected virtual IReadOnlyList <MigrationOperation> Sort(
            [NotNull] IEnumerable <MigrationOperation> operations,
            [NotNull] DiffContext diffContext)
        {
            Check.NotNull(operations, nameof(operations));

            var dropForeignKeyOperations = new List <MigrationOperation>();
            var dropOperations           = new List <MigrationOperation>();
            var dropColumnOperations     = new List <MigrationOperation>();
            var dropTableOperations      = new List <DropTableOperation>();
            var ensureSchemaOperations   = new List <MigrationOperation>();
            var createSequenceOperations = new List <MigrationOperation>();
            var createTableOperations    = new List <CreateTableOperation>();
            var alterOperations          = new List <MigrationOperation>();
            var renameOperations         = new List <MigrationOperation>();
            var renameIndexOperations    = new List <MigrationOperation>();
            var renameTableOperations    = new List <MigrationOperation>();
            var leftovers = new List <MigrationOperation>();

            foreach (var operation in operations)
            {
                var type = operation.GetType();
                if (type == typeof(DropForeignKeyOperation))
                {
                    dropForeignKeyOperations.Add(operation);
                }
                else if (_dropOperationTypes.Contains(type))
                {
                    dropOperations.Add(operation);
                }
                else if (type == typeof(DropColumnOperation))
                {
                    dropColumnOperations.Add(operation);
                }
                else if (type == typeof(DropTableOperation))
                {
                    dropTableOperations.Add((DropTableOperation)operation);
                }
                else if (type == typeof(EnsureSchemaOperation))
                {
                    ensureSchemaOperations.Add(operation);
                }
                else if (type == typeof(CreateSequenceOperation))
                {
                    createSequenceOperations.Add(operation);
                }
                else if (type == typeof(CreateTableOperation))
                {
                    createTableOperations.Add((CreateTableOperation)operation);
                }
                else if (_alterOperationTypes.Contains(type))
                {
                    alterOperations.Add(operation);
                }
                else if (_renameOperationTypes.Contains(type))
                {
                    renameOperations.Add(operation);
                }
                else if (type == typeof(RenameIndexOperation))
                {
                    renameIndexOperations.Add(operation);
                }
                else if (type == typeof(RenameTableOperation))
                {
                    renameTableOperations.Add(operation);
                }
                else
                {
                    Debug.Assert(false, "Unexpected operation type: " + operation.GetType());
                    leftovers.Add(operation);
                }
            }

            var createTableGraph = new Multigraph <CreateTableOperation, AddForeignKeyOperation>();

            createTableGraph.AddVertices(createTableOperations);
            foreach (var createTableOperation in createTableOperations)
            {
                foreach (var addForeignKeyOperation in createTableOperation.ForeignKeys)
                {
                    if ((addForeignKeyOperation.Table == addForeignKeyOperation.PrincipalTable) &&
                        (addForeignKeyOperation.Schema == addForeignKeyOperation.PrincipalSchema))
                    {
                        continue;
                    }

                    var principalCreateTableOperation = createTableOperations.FirstOrDefault(
                        o => (o.Name == addForeignKeyOperation.PrincipalTable) &&
                        (o.Schema == addForeignKeyOperation.PrincipalSchema));
                    if (principalCreateTableOperation != null)
                    {
                        createTableGraph.AddEdge(principalCreateTableOperation, createTableOperation, addForeignKeyOperation);
                    }
                }
            }
            createTableOperations = createTableGraph.TopologicalSort(
                (principalCreateTableOperation, createTableOperation, addForeignKeyOperations) =>
            {
                foreach (var addForeignKeyOperation in addForeignKeyOperations)
                {
                    createTableOperation.ForeignKeys.Remove(addForeignKeyOperation);
                    alterOperations.Add(addForeignKeyOperation);
                }

                return(true);
            }).ToList();

            var dropTableGraph = new Multigraph <DropTableOperation, IForeignKey>();

            dropTableGraph.AddVertices(dropTableOperations);
            foreach (var dropTableOperation in dropTableOperations)
            {
                var entityType = diffContext.GetMetadata(dropTableOperation);
                foreach (var foreignKey in GetForeignKeysInHierarchy(entityType))
                {
                    var principalRootEntityType = foreignKey.PrincipalEntityType.RootType();
                    if (entityType == principalRootEntityType)
                    {
                        continue;
                    }

                    var principalDropTableOperation = diffContext.FindDrop(principalRootEntityType);
                    if (principalDropTableOperation != null)
                    {
                        dropTableGraph.AddEdge(dropTableOperation, principalDropTableOperation, foreignKey);
                    }
                }
            }
            var newDiffContext = new DiffContext();

            dropTableOperations = dropTableGraph.TopologicalSort(
                (dropTableOperation, principalDropTableOperation, foreignKeys) =>
            {
                dropForeignKeyOperations.AddRange(foreignKeys.SelectMany(c => Remove(c, newDiffContext)));

                return(true);
            }).ToList();

            return(dropForeignKeyOperations
                   .Concat(dropOperations)
                   .Concat(dropColumnOperations)
                   .Concat(dropTableOperations)
                   .Concat(ensureSchemaOperations)
                   .Concat(createSequenceOperations)
                   .Concat(createTableOperations)
                   .Concat(alterOperations)
                   .Concat(renameOperations)
                   .Concat(renameIndexOperations)
                   .Concat(renameTableOperations)
                   .Concat(leftovers)
                   .ToArray());
        }
        protected virtual IReadOnlyList <MigrationOperation> Sort([NotNull] IEnumerable <MigrationOperation> operations)
        {
            Check.NotNull(operations, nameof(operations));

            var dropOperations           = new List <MigrationOperation>();
            var dropColumnOperations     = new List <MigrationOperation>();
            var dropTableOperations      = new List <MigrationOperation>();
            var dropSchemaOperations     = new List <MigrationOperation>();
            var createSchemaOperations   = new List <MigrationOperation>();
            var createSequenceOperations = new List <MigrationOperation>();
            var createTableOperations    = new Dictionary <string, CreateTableOperation>();
            var alterOperations          = new List <MigrationOperation>();
            var renameOperations         = new List <MigrationOperation>();
            var renameIndexOperations    = new List <MigrationOperation>();
            var renameTableOperations    = new List <MigrationOperation>();
            var leftovers = new List <MigrationOperation>();

            foreach (var operation in operations)
            {
                var type = operation.GetType();
                if (_dropOperationTypes.Contains(type))
                {
                    dropOperations.Add(operation);
                }
                else if (type == typeof(DropColumnOperation))
                {
                    dropColumnOperations.Add(operation);
                }
                else if (type == typeof(DropTableOperation))
                {
                    dropTableOperations.Add(operation);
                }
                else if (type == typeof(DropSchemaOperation))
                {
                    dropSchemaOperations.Add(operation);
                }
                else if (type == typeof(CreateSchemaOperation))
                {
                    createSchemaOperations.Add(operation);
                }
                else if (type == typeof(CreateSequenceOperation))
                {
                    createSequenceOperations.Add(operation);
                }
                else if (type == typeof(CreateTableOperation))
                {
                    var createTableOperation = (CreateTableOperation)operation;

                    createTableOperations.Add(
                        createTableOperation.Schema + ":" + createTableOperation.Name,
                        createTableOperation);
                }
                else if (_alterOperationTypes.Contains(type))
                {
                    alterOperations.Add(operation);
                }
                else if (_renameOperationTypes.Contains(type))
                {
                    renameOperations.Add(operation);
                }
                else if (type == typeof(RenameIndexOperation))
                {
                    renameIndexOperations.Add(operation);
                }
                else if (type == typeof(RenameTableOperation))
                {
                    renameTableOperations.Add(operation);
                }
                else
                {
                    Debug.Assert(false, "Unexpected operation type: " + operation.GetType());
                    leftovers.Add(operation);
                }
            }

            var createTableGraph = new Multigraph <string, AddForeignKeyOperation>();

            createTableGraph.AddVertices(createTableOperations.Keys);
            foreach (var pair in createTableOperations)
            {
                foreach (var addForeignKeyOperation in pair.Value.ForeignKeys)
                {
                    var principalTable = addForeignKeyOperation.ReferencedSchema + ":" + addForeignKeyOperation.ReferencedTable;
                    if (principalTable == pair.Key)
                    {
                        continue;
                    }
                    if (!createTableOperations.ContainsKey(principalTable))
                    {
                        continue;
                    }
                    createTableGraph.AddEdge(principalTable, pair.Key, addForeignKeyOperation);
                }
            }
            var sortedCreateTableOperations = createTableGraph.TopologicalSort(
                (principalTable, key, foreignKeyOperations) =>
            {
                foreach (var foreignKeyOperation in foreignKeyOperations)
                {
                    createTableOperations[key].ForeignKeys.Remove(foreignKeyOperation);
                    alterOperations.Add(foreignKeyOperation);
                }
                return(true);
            })
                                              .Select(k => createTableOperations[k]);

            return(dropOperations
                   .Concat(dropColumnOperations)
                   .Concat(dropTableOperations)
                   .Concat(dropSchemaOperations)
                   .Concat(createSchemaOperations)
                   .Concat(createSequenceOperations)
                   .Concat(sortedCreateTableOperations)
                   .Concat(alterOperations)
                   .Concat(renameOperations)
                   .Concat(renameIndexOperations)
                   .Concat(renameTableOperations)
                   .Concat(leftovers)
                   .ToArray());
        }
        private void AddForeignKeyEdges(
            Multigraph<ModificationCommand, IForeignKey> commandGraph,
            Dictionary<IKeyValueIndex, List<ModificationCommand>> predecessorsMap)
        {
            foreach (var command in commandGraph.Vertices)
            {
                if ((command.EntityState == EntityState.Modified)
                    || (command.EntityState == EntityState.Added))
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var keyValueIndexFactory = _keyValueIndexFactoryFactory.GetKeyValueIndexFactory(foreignKey.PrincipalKey);
                            var dependentKeyValue = keyValueIndexFactory.CreateDependentKeyValue((InternalEntityEntry)entry, foreignKey);
                            if (dependentKeyValue == null)
                            {
                                continue;
                            }

                            AddMatchingPredecessorEdge(predecessorsMap, dependentKeyValue, commandGraph, command, foreignKey);

                            if (!foreignKey.IsUnique)
                            {
                                continue;
                            }

                            // If the current value set is in use by another entry which is being deleted then the
                            // CurrentValue of this entry matches with the OriginalValue of entry being deleted.
                            // To compare both the KeyValueIndex as same, set the ValueType to Original while the values are Current
                            dependentKeyValue = dependentKeyValue.WithOriginalValuesFlag();
                            AddMatchingPredecessorEdge(predecessorsMap, dependentKeyValue, commandGraph, command, foreignKey);
                        }
                    }
                }

                // TODO: also examine modified entities here when principal key modification is supported
                if (command.EntityState == EntityState.Deleted)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.GetReferencingForeignKeys())
                        {
                            var keyValueIndexFactory = _keyValueIndexFactoryFactory.GetKeyValueIndexFactory(foreignKey.PrincipalKey);
                            var principalKeyValue = keyValueIndexFactory.CreatePrincipalKeyValueFromOriginalValues((InternalEntityEntry)entry, foreignKey);
                            if (principalKeyValue != null)
                            {
                                AddMatchingPredecessorEdge(predecessorsMap, principalKeyValue, commandGraph, command, foreignKey);
                            }
                        }
                    }
                }
            }
        }
 private static void AddMatchingPredecessorEdge(
     Dictionary<IKeyValueIndex, List<ModificationCommand>> predecessorsMap,
     IKeyValueIndex dependentKeyValue,
     Multigraph<ModificationCommand, IForeignKey> commandGraph,
     ModificationCommand command,
     IForeignKey foreignKey)
 {
     List<ModificationCommand> predecessorCommands;
     if (predecessorsMap.TryGetValue(dependentKeyValue, out predecessorCommands))
     {
         foreach (var predecessor in predecessorCommands)
         {
             if (predecessor != command)
             {
                 commandGraph.AddEdge(predecessor, command, foreignKey);
             }
         }
     }
 }
Example #18
0
        private IEnumerable <IProperty> GetSortedProperties(IEntityType entityType)
        {
            var schema                     = _cassandraOptionsExtension.DefaultKeyspace;
            var shadowProperties           = new List <IProperty>();
            var shadowPrimaryKeyProperties = new List <IProperty>();
            var primaryKeyPropertyGroups   = new Dictionary <PropertyInfo, IProperty>();
            var groups                     = new Dictionary <PropertyInfo, List <IProperty> >();
            var unorderedGroups            = new Dictionary <PropertyInfo, SortedDictionary <int, IProperty> >();
            var types = new Dictionary <Type, SortedDictionary <int, PropertyInfo> >();
            var model = entityType.Model;
            var declaredProperties = entityType.GetDeclaredProperties().ToList();

            declaredProperties.AddRange(entityType.ClrType.GetProperties().Where(p =>
            {
                var et = model.FindEntityType(p.PropertyType);
                if (et == null || !et.IsUserDefinedType())
                {
                    return(false);
                }

                return(true);
            }).Select(p => new Property(p.Name, p.PropertyType, null, null, entityType as EntityType, ConfigurationSource.Convention, null)).ToList());
            foreach (var property in declaredProperties)
            {
                var clrProperty = property.PropertyInfo;
                if (clrProperty == null)
                {
                    if (property.IsPrimaryKey())
                    {
                        shadowPrimaryKeyProperties.Add(property);

                        continue;
                    }

                    var foreignKey = property.GetContainingForeignKeys()
                                     .FirstOrDefault(fk => fk.DependentToPrincipal?.PropertyInfo != null);
                    if (foreignKey == null)
                    {
                        shadowProperties.Add(property);

                        continue;
                    }

                    clrProperty = foreignKey.DependentToPrincipal.PropertyInfo;
                    var groupIndex = foreignKey.Properties.IndexOf(property);

                    unorderedGroups.GetOrAddNew(clrProperty).Add(groupIndex, property);
                }
                else
                {
                    if (property.IsPrimaryKey())
                    {
                        primaryKeyPropertyGroups.Add(clrProperty, property);
                    }

                    groups.Add(
                        clrProperty, new List <IProperty> {
                        property
                    });
                }

                var clrType = clrProperty.DeclaringType;
                var index   = clrType.GetTypeInfo().DeclaredProperties
                              .IndexOf(clrProperty, PropertyInfoEqualityComparer.Instance);

                types.GetOrAddNew(clrType)[index] = clrProperty;
            }

            foreach (var group in unorderedGroups)
            {
                groups.Add(group.Key, group.Value.Values.ToList());
            }

            foreach (var definingForeignKey in entityType.GetDeclaredReferencingForeignKeys()
                     .Where(
                         fk => fk.DeclaringEntityType.GetRootType() != entityType.GetRootType() &&
                         fk.DeclaringEntityType.GetTableName() == entityType.GetTableName() &&
                         fk.DeclaringEntityType.GetSchema() == schema &&
                         fk
                         == fk.DeclaringEntityType
                         .FindForeignKey(
                             fk.DeclaringEntityType.FindPrimaryKey().Properties,
                             entityType.FindPrimaryKey(),
                             entityType)))
            {
                var clrProperty = definingForeignKey.PrincipalToDependent?.PropertyInfo;
                var properties  = GetSortedProperties(definingForeignKey.DeclaringEntityType).ToList();
                if (clrProperty == null)
                {
                    shadowProperties.AddRange(properties);

                    continue;
                }

                groups.Add(clrProperty, properties);

                var clrType = clrProperty.DeclaringType;
                var index   = clrType.GetTypeInfo().DeclaredProperties
                              .IndexOf(clrProperty, PropertyInfoEqualityComparer.Instance);

                types.GetOrAddNew(clrType)[index] = clrProperty;
            }

            var graph = new Multigraph <Type, object>();

            graph.AddVertices(types.Keys);

            foreach (var left in types.Keys)
            {
                var found = false;
                foreach (var baseType in left.GetBaseTypes())
                {
                    foreach (var right in types.Keys)
                    {
                        if (right == baseType)
                        {
                            graph.AddEdge(right, left, null);
                            found = true;

                            break;
                        }
                    }

                    if (found)
                    {
                        break;
                    }
                }
            }

            var sortedPropertyInfos = graph.TopologicalSort().SelectMany(e => types[e].Values).ToList();

            return(sortedPropertyInfos
                   .Select(pi => primaryKeyPropertyGroups.ContainsKey(pi) ? primaryKeyPropertyGroups[pi] : null)
                   .Where(e => e != null)
                   .Concat(shadowPrimaryKeyProperties)
                   .Concat(sortedPropertyInfos.Where(pi => !primaryKeyPropertyGroups.ContainsKey(pi)).SelectMany(p => groups[p]))
                   .Concat(shadowProperties)
                   .Concat(entityType.GetDirectlyDerivedTypes().SelectMany(GetSortedProperties)));
        }
Example #19
0
        // Builds a map from foreign key values to list of modification commands, with an entry for every command
        // that may need to precede some other command involving that foreign key value.
        private Dictionary <IKeyValueIndex, List <ModificationCommand> > CreateKeyValuePredecessorMap(
            Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            var predecessorsMap = new Dictionary <IKeyValueIndex, List <ModificationCommand> >();

            foreach (var command in commandGraph.Vertices)
            {
                var columnModifications = command.ColumnModifications;
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var i = 0; i < command.Entries.Count; i++)
                    {
                        var entry = command.Entries[i];
                        // TODO: Perf: Consider only adding foreign keys defined on entity types involved in a modification
                        foreach (var foreignKey in entry.EntityType.GetReferencingForeignKeys())
                        {
                            var keyValueIndexFactory =
                                _keyValueIndexFactorySource.GetKeyValueIndexFactory(foreignKey.PrincipalKey);

                            var candidateKeyValueColumnModifications = columnModifications.Where(
                                cm =>
                                foreignKey.PrincipalKey.Properties.Contains(cm.Property) &&
                                (cm.IsWrite || cm.IsRead));

                            if (command.EntityState == EntityState.Added ||
                                candidateKeyValueColumnModifications.Any())
                            {
                                var principalKeyValue =
                                    keyValueIndexFactory.CreatePrincipalKeyValue((InternalEntityEntry)entry, foreignKey);

                                if (principalKeyValue != null)
                                {
                                    if (!predecessorsMap.TryGetValue(principalKeyValue, out var predecessorCommands))
                                    {
                                        predecessorCommands = new List <ModificationCommand>();
                                        predecessorsMap.Add(principalKeyValue, predecessorCommands);
                                    }

                                    predecessorCommands.Add(command);
                                }
                            }
                        }
                    }
                }

                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Deleted)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var keyValueIndexFactory = _keyValueIndexFactorySource.GetKeyValueIndexFactory(foreignKey.PrincipalKey);

                            var currentForeignKey = foreignKey;
                            var foreignKeyValueColumnModifications = columnModifications.Where(
                                cm =>
                                currentForeignKey.Properties.Contains(cm.Property) && (cm.IsWrite || cm.IsRead));

                            if (command.EntityState == EntityState.Deleted ||
                                foreignKeyValueColumnModifications.Any())
                            {
                                var dependentKeyValue =
                                    keyValueIndexFactory.CreateDependentKeyValueFromOriginalValues((InternalEntityEntry)entry, foreignKey);

                                if (dependentKeyValue != null)
                                {
                                    if (!predecessorsMap.TryGetValue(dependentKeyValue, out var predecessorCommands))
                                    {
                                        predecessorCommands = new List <ModificationCommand>();
                                        predecessorsMap.Add(dependentKeyValue, predecessorCommands);
                                    }

                                    predecessorCommands.Add(command);
                                }
                            }
                        }
                    }
                }
            }

            return(predecessorsMap);
        }
Example #20
0
        private void AddUniqueValueEdges(Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            Dictionary <IIndex, Dictionary <object[], ModificationCommand> > predecessorsMap = null;

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState != EntityState.Modified &&
                    command.EntityState != EntityState.Deleted)
                {
                    continue;
                }

                for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                {
                    var entry = command.Entries[entryIndex];
                    foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique))
                    {
                        if (command.EntityState != EntityState.Deleted)
                        {
                            var indexColumnModifications = false;
                            // ReSharper disable once ForCanBeConvertedToForeach
                            // ReSharper disable once LoopCanBeConvertedToQuery
                            for (var indexIndex = 0; indexIndex < command.ColumnModifications.Count; indexIndex++)
                            {
                                var cm = command.ColumnModifications[indexIndex];
                                if (index.Properties.Contains(cm.Property) &&
                                    (cm.IsWrite || cm.IsRead))
                                {
                                    indexColumnModifications = true;
                                    break;
                                }
                            }

                            if (!indexColumnModifications)
                            {
                                continue;
                            }
                        }

                        var valueFactory = index.GetNullableValueFactory <object[]>();
                        if (valueFactory.TryCreateFromOriginalValues(
                                (InternalEntityEntry)entry, out var indexValue))
                        {
                            predecessorsMap ??= new Dictionary <IIndex, Dictionary <object[], ModificationCommand> >();
                            if (!predecessorsMap.TryGetValue(index, out var predecessorCommands))
                            {
                                predecessorCommands =
                                    new Dictionary <object[], ModificationCommand>(valueFactory.EqualityComparer);
                                predecessorsMap.Add(index, predecessorCommands);
                            }

                            if (!predecessorCommands.ContainsKey(indexValue))
                            {
                                predecessorCommands.Add(indexValue, command);
                            }
                        }
                    }
                }
            }

            if (predecessorsMap == null)
            {
                return;
            }

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique))
                        {
                            var indexColumnModifications =
                                command.ColumnModifications.Where(
                                    cm => index.Properties.Contains(cm.Property) &&
                                    cm.IsWrite);

                            if (command.EntityState == EntityState.Added ||
                                indexColumnModifications.Any())
                            {
                                var valueFactory = index.GetNullableValueFactory <object[]>();
                                if (valueFactory.TryCreateFromCurrentValues((InternalEntityEntry)entry, out var indexValue) &&
                                    predecessorsMap.TryGetValue(index, out var predecessorCommands) &&
                                    predecessorCommands.TryGetValue(indexValue, out var predecessor) &&
                                    predecessor != command)
                                {
                                    commandGraph.AddEdge(predecessor, command, index);
                                }
                            }
                        }
                    }
                }
            }
        }
Example #21
0
        public void TopologicalSort_can_break_two_cycles()
        {
            var vertexOne = new Vertex {
                Id = 1
            };
            var vertexTwo = new Vertex {
                Id = 2
            };
            var vertexThree = new Vertex {
                Id = 3
            };
            var vertexFour = new Vertex {
                Id = 4
            };
            var vertexFive = new Vertex {
                Id = 5
            };

            var edgeOne = new Edge {
                Id = 1
            };
            var edgeTwo = new Edge {
                Id = 2
            };
            var edgeThree = new Edge {
                Id = 3
            };
            var edgeFour = new Edge {
                Id = 4
            };
            var edgeFive = new Edge {
                Id = 5
            };
            var edgeSix = new Edge {
                Id = 6
            };

            var graph = new Multigraph <Vertex, Edge>();

            graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree, vertexFour, vertexFive });

            // 1 -> {2, 4}
            graph.AddEdge(vertexOne, vertexTwo, edgeOne);
            graph.AddEdge(vertexOne, vertexFour, edgeTwo);
            // 2 -> {3}
            graph.AddEdge(vertexTwo, vertexThree, edgeThree);
            // 3 -> {1}
            graph.AddEdge(vertexThree, vertexOne, edgeFour);
            // 4 -> {5}
            graph.AddEdge(vertexFour, vertexFive, edgeFive);
            // 5 -> {1}
            graph.AddEdge(vertexFive, vertexOne, edgeSix);

            Assert.Equal(
                new[] { vertexTwo, vertexThree, vertexOne, vertexFour, vertexFive },
                graph.TopologicalSort(
                    (from, to, edges) =>
            {
                var edge = edges.Single();
                return(edge == edgeOne || edge == edgeSix);
            }).ToArray());
        }
Example #22
0
        public void BatchingTopologicalSort_throws_with_formatted_message_with_no_tail_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 vertexFour = new Vertex {
                Id = 4
            };

            var edgeOne = new Edge {
                Id = 1
            };
            var edgeTwo = new Edge {
                Id = 2
            };
            var edgeThree = new Edge {
                Id = 3
            };
            var edgeFour = new Edge {
                Id = 4
            };

            var graph = new Multigraph <Vertex, Edge>();

            graph.AddVertices(new[] { vertexOne, vertexTwo, vertexThree, vertexFour });

            // 2 -> {1}
            graph.AddEdge(vertexTwo, vertexOne, edgeOne);
            // 3 -> {2}
            graph.AddEdge(vertexThree, vertexTwo, edgeTwo);
            // 4 -> {3}
            graph.AddEdge(vertexFour, vertexThree, edgeThree);
            // 3 -> {4}
            graph.AddEdge(vertexThree, vertexFour, edgeFour);

            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(
                CoreStrings.CircularDependency(message),
                Assert.Throws <InvalidOperationException>(() => graph.BatchingTopologicalSort(formatter)).Message);

            Assert.Equal(2, cycleData.Count);

            Assert.Equal(vertexFour, cycleData[vertexThree].Item2);
            Assert.Equal(new[] { edgeFour }, cycleData[vertexThree].Item3);

            Assert.Equal(vertexThree, cycleData[vertexFour].Item2);
            Assert.Equal(new[] { edgeThree }, cycleData[vertexFour].Item3);
        }
Example #23
0
        private void AddUniqueValueEdges(Multigraph <ModificationCommand, IAnnotatable> commandGraph)
        {
            Dictionary <IIndex, Dictionary <object[], ModificationCommand> > predecessorsMap = null;

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Deleted)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique))
                        {
                            var indexColumnModifications =
                                command.ColumnModifications.Where(
                                    cm =>
                                    index.Properties.Contains(cm.Property) &&
                                    (cm.IsWrite || cm.IsRead));

                            if (command.EntityState == EntityState.Deleted ||
                                indexColumnModifications.Any())
                            {
                                var valueFactory = index.GetNullableValueFactory <object[]>();
                                if (valueFactory.TryCreateFromOriginalValues((InternalEntityEntry)entry, out var indexValue))
                                {
                                    predecessorsMap = predecessorsMap ?? new Dictionary <IIndex, Dictionary <object[], ModificationCommand> >();
                                    if (!predecessorsMap.TryGetValue(index, out var predecessorCommands))
                                    {
                                        predecessorCommands = new Dictionary <object[], ModificationCommand>(valueFactory.EqualityComparer);
                                        predecessorsMap.Add(index, predecessorCommands);
                                    }
                                    predecessorCommands.Add(indexValue, command);
                                }
                            }
                        }
                    }
                }
            }

            if (predecessorsMap == null)
            {
                return;
            }

            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var index in entry.EntityType.GetIndexes().Where(i => i.IsUnique))
                        {
                            var indexColumnModifications =
                                command.ColumnModifications.Where(
                                    cm =>
                                    index.Properties.Contains(cm.Property) &&
                                    cm.IsWrite);

                            if (command.EntityState == EntityState.Added ||
                                indexColumnModifications.Any())
                            {
                                var valueFactory = index.GetNullableValueFactory <object[]>();
                                if (valueFactory.TryCreateFromCurrentValues((InternalEntityEntry)entry, out var indexValue) &&
                                    predecessorsMap.TryGetValue(index, out var predecessorCommands) &&
                                    predecessorCommands.TryGetValue(indexValue, out var predecessor) &&
                                    predecessor != command)
                                {
                                    commandGraph.AddEdge(predecessor, command, index);
                                }
                            }
                        }
                    }
                }
            }
        }
        private void AddForeignKeyEdges(
            Multigraph <ModificationCommand, IForeignKey> commandGraph,
            Dictionary <KeyValue, List <ModificationCommand> > predecessorsMap)
        {
            foreach (var command in commandGraph.Vertices)
            {
                if (command.EntityState == EntityState.Modified ||
                    command.EntityState == EntityState.Added)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var dependentKeyValue = CreateDependentKeyValue(entry, foreignKey, ValueType.Current);

                            if (dependentKeyValue.Key != EntityKey.InvalidEntityKey)
                            {
                                List <ModificationCommand> predecessorCommands;
                                if (predecessorsMap.TryGetValue(dependentKeyValue, out predecessorCommands))
                                {
                                    foreach (var predecessor in predecessorCommands)
                                    {
                                        if (predecessor != command)
                                        {
                                            commandGraph.AddEdge(predecessor, command, foreignKey);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // TODO: also examine modified entities here when principal key modification is supported
                if (command.EntityState == EntityState.Deleted)
                {
                    foreach (var entry in command.Entries)
                    {
                        foreach (var foreignKey in entry.EntityType.FindReferencingForeignKeys())
                        {
                            var principalKeyValue = CreatePrincipalKeyValue(entry.OriginalValues, foreignKey, ValueType.Original);

                            if (principalKeyValue.Key != EntityKey.InvalidEntityKey)
                            {
                                List <ModificationCommand> predecessorCommands;
                                if (predecessorsMap.TryGetValue(principalKeyValue, out predecessorCommands))
                                {
                                    foreach (var predecessor in predecessorCommands)
                                    {
                                        if (predecessor != command)
                                        {
                                            commandGraph.AddEdge(predecessor, command, foreignKey);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        private void AddForeignKeyEdges(
            Multigraph <ModificationCommand, IAnnotatable> commandGraph,
            Dictionary <IKeyValueIndex, List <ModificationCommand> > predecessorsMap)
        {
            foreach (var command in commandGraph.Vertices)
            {
                if (command.Predecessor != null)
                {
                    // This is usually an implicit relationship between TPT rows for the same entity
                    commandGraph.AddEdge(command.Predecessor, command, null);
                }

                switch (command.EntityState)
                {
                case EntityState.Modified:
                case EntityState.Added:
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                    {
                        var entry = command.Entries[entryIndex];
                        foreach (var foreignKey in entry.EntityType.GetForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints();

                            if (!constraints.Any() ||
                                (command.EntityState == EntityState.Modified &&
                                 !foreignKey.Properties.Any(p => entry.IsModified(p))))
                            {
                                continue;
                            }

                            var dependentKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreateDependentKeyValue(entry, foreignKey);
                            if (dependentKeyValue == null)
                            {
                                continue;
                            }

                            AddMatchingPredecessorEdge(
                                predecessorsMap, dependentKeyValue, commandGraph, command, foreignKey);
                        }
                    }

                    break;

                case EntityState.Deleted:
                    // ReSharper disable once ForCanBeConvertedToForeach
                    for (var entryIndex = 0; entryIndex < command.Entries.Count; entryIndex++)
                    {
                        var entry = command.Entries[entryIndex];
                        foreach (var foreignKey in entry.EntityType.GetReferencingForeignKeys())
                        {
                            var constraints = foreignKey.GetMappedConstraints()
                                              .Where(c => c.PrincipalTable.Name == command.TableName && c.PrincipalTable.Schema == command.Schema);
                            if (!constraints.Any())
                            {
                                continue;
                            }

                            var principalKeyValue = _keyValueIndexFactorySource
                                                    .GetKeyValueIndexFactory(foreignKey.PrincipalKey)
                                                    .CreatePrincipalKeyValueFromOriginalValues(entry, foreignKey);
                            if (principalKeyValue != null)
                            {
                                AddMatchingPredecessorEdge(
                                    predecessorsMap, principalKeyValue, commandGraph, command, foreignKey);
                            }
                        }
                    }

                    break;
                }
            }
        }