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