protected virtual DropForeignKeyOperation Drop(DatabaseForeignKey foreignKey)
 => new DropForeignKeyOperation
 {
     Name   = foreignKey.Name,
     Table  = foreignKey.Table.Name,
     Schema = foreignKey.Table.Schema
 };
 void GetConstraints()
 {
     foreach (var x in _tables)
     {
         using (var command = new MySqlCommand(string.Format(GetConstraintsQuery, _connection.Database, x.Key.Replace("`", "")), _connection))
             using (var reader = command.ExecuteReader())
                 while (reader.Read())
                 {
                     if (_tables.ContainsKey($"`{ reader.GetString(2) }`"))
                     {
                         var fkInfo = new DatabaseForeignKey
                         {
                             Name           = reader.GetString(0),
                             OnDelete       = ConvertToReferentialAction(reader.GetString(4)),
                             Table          = x.Value,
                             PrincipalTable = _tables[$"`{ reader.GetString(2) }`"]
                         };
                         foreach (var pair in reader.GetString(3).Split(','))
                         {
                             fkInfo.Columns.Add(x.Value.Columns.Single(y => y.Name == pair.Split('|')[0]));
                             fkInfo.PrincipalColumns.Add(fkInfo.PrincipalTable.Columns.Single(y => y.Name == pair.Split('|')[1]));
                         }
                         x.Value.ForeignKeys.Add(fkInfo);
                     }
                     else
                     {
                         Logger.LogWarning($"Referenced table `{ reader.GetString(2) }` is not in dictionary.");
                     }
                 }
     }
 }
Exemple #3
0
        private void GetConstraints(DbConnection connection, IReadOnlyList <DatabaseTable> tables)
        {
            foreach (var table in tables)
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = string.Format(GetConstraintsQuery, table.Name);
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var referencedTableName = reader.GetString(2);
                            var referencedTable     = tables.First(t => t.Name == referencedTableName);
                            var fkInfo = new DatabaseForeignKey {
                                Name = reader.GetString(0), OnDelete = ConvertToReferentialAction(reader.GetString(4)), Table = table, PrincipalTable = referencedTable
                            };
                            foreach (var pair in reader.GetString(3).Split(','))
                            {
                                fkInfo.Columns.Add(table.Columns.Single(y =>
                                                                        string.Equals(y.Name, pair.Split('|')[0], StringComparison.OrdinalIgnoreCase)));
                                fkInfo.PrincipalColumns.Add(fkInfo.PrincipalTable.Columns.Single(y =>
                                                                                                 string.Equals(y.Name, pair.Split('|')[1], StringComparison.OrdinalIgnoreCase)));
                            }

                            table.ForeignKeys.Add(fkInfo);
                        }
                    }
                }
            }
        }
        private static void AssignOnDeleteAction(
            DatabaseForeignKey databaseForeignKey, IMutableForeignKey foreignKey)
        {
            if (databaseForeignKey == null)
            {
                throw new ArgumentNullException(nameof(databaseForeignKey));
            }
            if (foreignKey == null)
            {
                throw new ArgumentNullException(nameof(foreignKey));
            }

            switch (databaseForeignKey.OnDelete)
            {
            case ReferentialAction.Cascade:
                foreignKey.DeleteBehavior = DeleteBehavior.Cascade;
                break;

            case ReferentialAction.SetNull:
                foreignKey.DeleteBehavior = DeleteBehavior.SetNull;
                break;

            default:
                foreignKey.DeleteBehavior = DeleteBehavior.ClientSetNull;
                break;
            }
        }
Exemple #5
0
 public ForeignKey(DatabaseForeignKey source)
 {
     Name             = source.Name;
     PrincipalTable   = source.PrincipalTable.Name;
     PrincipalColumns = source.PrincipalColumns.Select(x => x.Name).ToList();
     Columns          = source.Columns.Select(x => x.Name).ToList();
     OnDelete         = source.OnDelete;
 }
        private void GetForeignKeys(TSqlTable table, DatabaseModel dbModel)
        {
            var dbTable = dbModel.Tables
                          .Single(t => t.Name == table.Name.Parts[1] &&
                                  t.Schema == table.Name.Parts[0]);

            var fks = table.ForeignKeyConstraints.ToList();

            foreach (var fk in fks)
            {
                var foreignTable = dbModel.Tables
                                   .SingleOrDefault(t => t.Name == fk.ForeignTable.First().Name.Parts[1] &&
                                                    t.Schema == fk.ForeignTable.First().Name.Parts[0]);

                if (foreignTable == null)
                {
                    continue;
                }

                var foreignKey = new DatabaseForeignKey
                {
                    Name           = fk.Name.HasName ? fk.Name.Parts[1] : null,
                    Table          = dbTable,
                    PrincipalTable = foreignTable,
                    OnDelete       = ConvertToReferentialAction(fk.DeleteAction)
                };

                foreach (var fkCol in fk.Columns)
                {
                    var dbCol = dbTable.Columns
                                .Single(c => c.Name == fkCol.Name.Parts[2]);

                    foreignKey.Columns.Add(dbCol);
                }

                foreach (var fkCol in fk.ForeignColumns)
                {
                    var dbCol = foreignTable.Columns
                                .SingleOrDefault(c => c.Name == fkCol.Name.Parts[2]);

                    if (dbCol != null)
                    {
                        foreignKey.PrincipalColumns.Add(dbCol);
                    }
                }

                if (foreignKey.PrincipalColumns.Count > 0)
                {
                    dbTable.ForeignKeys.Add(foreignKey);
                }
            }
        }
        protected virtual void GetConstraints(
            DbConnection connection,
            IReadOnlyList <DatabaseTable> tables)
        {
            foreach (var table in tables)
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = string.Format(GetConstraintsQuery, connection.Database, table.Name);
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var referencedTableName = reader.GetString(2);
                            var referencedTable     = tables.FirstOrDefault(t => t.Name == referencedTableName);
                            if (referencedTable == null)
                            {
                                // On operation systems with insensitive file name handling, the saved reference table name might have a
                                // different casing than the actual table name. (#1017)
                                // In the unlikely event that there are multiple tables with the same spelling, differing only in casing,
                                // we can't be certain which is the right match, so rather fail to be safe.
                                referencedTable = tables.Single(t => string.Equals(t.Name, referencedTableName, StringComparison.OrdinalIgnoreCase));
                            }
                            if (referencedTable != null)
                            {
                                var fkInfo = new DatabaseForeignKey {
                                    Name = reader.GetString(0), OnDelete = ConvertToReferentialAction(reader.GetString(4)), Table = table, PrincipalTable = referencedTable
                                };
                                foreach (var pair in reader.GetString(3).Split(','))
                                {
                                    fkInfo.Columns.Add(table.Columns.Single(y =>
                                                                            string.Equals(y.Name, pair.Split('|')[0], StringComparison.OrdinalIgnoreCase)));
                                    fkInfo.PrincipalColumns.Add(fkInfo.PrincipalTable.Columns.Single(y =>
                                                                                                     string.Equals(y.Name, pair.Split('|')[1], StringComparison.OrdinalIgnoreCase)));
                                }

                                table.ForeignKeys.Add(fkInfo);
                            }
                            else
                            {
                                _logger.Logger.LogWarning($"Referenced table `{referencedTableName}` is not in dictionary.");
                            }
                        }
                    }
                }
            }
        }
        private bool IsOneToOne(DatabaseForeignKey tableKeySchema, Relationship foreignRelationship)
        {
            var foreignColumn = foreignRelationship.Properties
                                .Select(p => p.ColumnName)
                                .FirstOrDefault();

            bool isFkeyPkey = tableKeySchema.PrincipalTable.PrimaryKey != null &&
                              tableKeySchema.Table.PrimaryKey != null &&
                              tableKeySchema.Table.PrimaryKey.Columns.Count == 1 &&
                              tableKeySchema.Table.PrimaryKey.Columns.Any(c => c.Name == foreignColumn);

            if (isFkeyPkey)
            {
                return(true);
            }

            return(false);
        }
        private static void AssignOnDeleteAction(
            [NotNull] DatabaseForeignKey databaseForeignKey, [NotNull] IMutableForeignKey foreignKey)
        {
            Check.NotNull(databaseForeignKey, nameof(databaseForeignKey));
            Check.NotNull(foreignKey, nameof(foreignKey));

            switch (databaseForeignKey.OnDelete)
            {
            case ReferentialAction.Cascade:
                foreignKey.DeleteBehavior = DeleteBehavior.Cascade;
                break;

            case ReferentialAction.SetNull:
                foreignKey.DeleteBehavior = DeleteBehavior.SetNull;
                break;

            default:
                foreignKey.DeleteBehavior = DeleteBehavior.ClientSetNull;
                break;
            }
        }
        private void GetConstraints()
        {
            foreach (var x in _tables)
            {
                using (var command =
                           new MySqlCommand(string.Format(GetConstraintsQuery, _connection.Database, x.Key),
                                            _connection))
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var referencedTableName = reader.GetString(2);
                            if (_tables.TryGetValue(referencedTableName, out var referencedTable))
                            {
                                var fkInfo = new DatabaseForeignKey
                                {
                                    Name           = reader.GetString(0),
                                    OnDelete       = ConvertToReferentialAction(reader.GetString(4)),
                                    Table          = x.Value,
                                    PrincipalTable = referencedTable
                                };
                                foreach (var pair in reader.GetString(3).Split(','))
                                {
                                    fkInfo.Columns.Add(x.Value.Columns.Single(y =>
                                                                              string.Equals(y.Name, pair.Split('|')[0], StringComparison.OrdinalIgnoreCase)));
                                    fkInfo.PrincipalColumns.Add(fkInfo.PrincipalTable.Columns.Single(y =>
                                                                                                     string.Equals(y.Name, pair.Split('|')[1], StringComparison.OrdinalIgnoreCase)));
                                }

                                x.Value.ForeignKeys.Add(fkInfo);
                            }
                            else
                            {
                                Logger.LogWarning($"Referenced table `{referencedTableName}` is not in dictionary.");
                            }
                        }
                    }
            }
        }
        private IEnumerable <DatabaseForeignKey> GetForeignKeys(DbConnection connection, DatabaseTable table, IList <DatabaseTable> tables)
        {
            using (var command1 = connection.CreateCommand())
            {
                command1.CommandText = new StringBuilder()
                                       .AppendLine("SELECT DISTINCT \"id\", \"table\", \"on_delete\"")
                                       .AppendLine("FROM pragma_foreign_key_list(@table)")
                                       .AppendLine("ORDER BY \"id\";")
                                       .ToString();

                var parameter1 = command1.CreateParameter();
                parameter1.ParameterName = "@table";
                parameter1.Value         = table.Name;
                command1.Parameters.Add(parameter1);

                using (var reader1 = command1.ExecuteReader())
                {
                    while (reader1.Read())
                    {
                        var id = reader1.GetInt64(0);
                        var principalTableName = reader1.GetString(1);
                        var onDelete           = reader1.GetString(2);
                        var foreignKey         = new DatabaseForeignKey
                        {
                            PrincipalTable = tables.FirstOrDefault(t => t.Name == principalTableName)
                                             ?? tables.FirstOrDefault(
                                t => t.Name.Equals(principalTableName, StringComparison.OrdinalIgnoreCase)),
                            OnDelete = ConvertToReferentialAction(onDelete)
                        };

                        _logger.ForeignKeyFound(table.Name, id, principalTableName, onDelete);

                        if (foreignKey.PrincipalTable == null)
                        {
                            _logger.ForeignKeyReferencesMissingTableWarning(id.ToString());
                            continue;
                        }

                        using (var command2 = connection.CreateCommand())
                        {
                            command2.CommandText = new StringBuilder()
                                                   .AppendLine("SELECT \"from\", \"to\"")
                                                   .AppendLine("FROM pragma_foreign_key_list(@table)")
                                                   .AppendLine("WHERE \"id\" = @id")
                                                   .AppendLine("ORDER BY \"seq\";")
                                                   .ToString();

                            var parameter2 = command2.CreateParameter();
                            parameter2.ParameterName = "@table";
                            parameter2.Value         = table.Name;
                            command2.Parameters.Add(parameter2);

                            var parameter3 = command2.CreateParameter();
                            parameter3.ParameterName = "@id";
                            parameter3.Value         = id;
                            command2.Parameters.Add(parameter3);

                            var invalid = false;

                            using (var reader2 = command2.ExecuteReader())
                            {
                                while (reader2.Read())
                                {
                                    var columnName = reader2.GetString(0);
                                    var column     = table.Columns.FirstOrDefault(c => c.Name == columnName)
                                                     ?? table.Columns.FirstOrDefault(
                                        c => c.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase));
                                    Debug.Assert(column != null, "column is null.");

                                    var principalColumnName = reader2.GetString(1);
                                    var principalColumn     =
                                        foreignKey.PrincipalTable.Columns.FirstOrDefault(c => c.Name == principalColumnName)
                                        ?? foreignKey.PrincipalTable.Columns.FirstOrDefault(
                                            c => c.Name.Equals(principalColumnName, StringComparison.OrdinalIgnoreCase));
                                    if (principalColumn == null)
                                    {
                                        invalid = true;
                                        _logger.ForeignKeyPrincipalColumnMissingWarning(
                                            id.ToString(), table.Name, principalColumnName, principalTableName);
                                        break;
                                    }

                                    foreignKey.Columns.Add(column);
                                    foreignKey.PrincipalColumns.Add(principalColumn);
                                }
                            }

                            if (!invalid)
                            {
                                yield return(foreignKey);
                            }
                        }
                    }
                }
            }
        }
Exemple #12
0
        void GetConstraints()
        {
            using (var command = new NpgsqlCommand(GetConstraintsQuery, _connection))
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var schemaName = reader.GetValueOrDefault <string>("nspname");
                        var tableName  = reader.GetValueOrDefault <string>("relname");

                        if (!_tableSelectionSet.Allows(schemaName, tableName))
                        {
                            continue;
                        }
                        var table   = _tables[TableKey(tableName, schemaName)];
                        var columns = (List <DatabaseColumn>)table.Columns;

                        var constraintName = reader.GetValueOrDefault <string>("conname");
                        var constraintType = reader.GetValueOrDefault <char>("contype");
                        switch (constraintType)
                        {
                        case 'p':
                            var primaryKey = new DatabasePrimaryKey
                            {
                                Table = table,
                                Name  = constraintName
                            };
                            var pkColumnIndices = reader.GetValueOrDefault <short[]>("conkey");
                            foreach (var pkColumnIndex in pkColumnIndices)
                            {
                                primaryKey.Columns.Add(columns[pkColumnIndex - 1]);
                            }
                            Debug.Assert(table.PrimaryKey == null);
                            table.PrimaryKey = primaryKey;
                            continue;

                        case 'f':
                            var foreignSchemaName = reader.GetValueOrDefault <string>("fr_nspname");
                            var foreignTableName  = reader.GetValueOrDefault <string>("fr_relname");
                            if (!_tables.TryGetValue(TableKey(foreignTableName, foreignSchemaName), out var principalTable))
                            {
                                continue;
                            }

                            var foreignKey = new DatabaseForeignKey
                            {
                                Name           = constraintName,
                                Table          = table,
                                PrincipalTable = principalTable,
                                OnDelete       = ConvertToReferentialAction(reader.GetValueOrDefault <char>("confdeltype"))
                            };

                            var columnIndices          = reader.GetValueOrDefault <short[]>("conkey");
                            var principalColumnIndices = reader.GetValueOrDefault <short[]>("confkey");
                            if (columnIndices.Length != principalColumnIndices.Length)
                            {
                                throw new Exception("Got varying lengths for column and principal column indices");
                            }

                            var principalColumns = (List <DatabaseColumn>)principalTable.Columns;

                            for (var i = 0; i < columnIndices.Length; i++)
                            {
                                foreignKey.Columns.Add(columns[columnIndices[i] - 1]);
                                foreignKey.PrincipalColumns.Add(principalColumns[principalColumnIndices[i] - 1]);
                            }

                            table.ForeignKeys.Add(foreignKey);
                            break;

                        default:
                            throw new NotSupportedException($"Unknown constraint type code {constraintType} for constraint {constraintName}");
                        }
                    }
                }
        }
 protected override bool AcceptForeignKey(DatabaseForeignKey foreignKey) => false;
Exemple #14
0
 /// <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>
 public static string DisplayName([NotNull] this DatabaseForeignKey foreignKey)
 => foreignKey.Table?.DisplayName() + "(" + string.Join(",", foreignKey.Columns.Select(f => f.Name)) + ")";
        private void CreateRelationship(EntityContext entityContext, Entity foreignEntity, DatabaseForeignKey tableKeySchema)
        {
            Entity primaryEntity = GetEntity(entityContext, tableKeySchema.PrincipalTable, false, false);

            string primaryName = primaryEntity.EntityClass;
            string foreignName = foreignEntity.EntityClass;

            string relationshipName = tableKeySchema.Name;

            relationshipName = _namer.UniqueRelationshipName(relationshipName);

            var  foreignMembers         = GetKeyMembers(foreignEntity, tableKeySchema.Columns, tableKeySchema.Name);
            bool foreignMembersRequired = foreignMembers.Any(c => c.IsRequired);

            var  primaryMembers         = GetKeyMembers(primaryEntity, tableKeySchema.PrincipalColumns, tableKeySchema.Name);
            bool primaryMembersRequired = primaryMembers.Any(c => c.IsRequired);

            // skip invalid fkeys
            if (foreignMembers.Count == 0 || primaryMembers.Count == 0)
            {
                return;
            }

            Relationship foreignRelationship = foreignEntity.Relationships
                                               .FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey);

            if (foreignRelationship == null)
            {
                foreignRelationship = new Relationship
                {
                    RelationshipName = relationshipName
                };
                foreignEntity.Relationships.Add(foreignRelationship);
            }
            foreignRelationship.IsMapped     = true;
            foreignRelationship.IsForeignKey = true;
            foreignRelationship.Cardinality  = foreignMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;

            foreignRelationship.PrimaryEntity     = primaryEntity;
            foreignRelationship.PrimaryProperties = new PropertyCollection(primaryMembers);

            foreignRelationship.Entity     = foreignEntity;
            foreignRelationship.Properties = new PropertyCollection(foreignMembers);

            string prefix = GetMemberPrefix(foreignRelationship, primaryName, foreignName);

            string foreignPropertyName = ToPropertyName(foreignEntity.EntityClass, prefix + primaryName);

            foreignPropertyName = _namer.UniqueName(foreignEntity.EntityClass, foreignPropertyName);
            foreignRelationship.PropertyName = foreignPropertyName;

            // add reverse
            Relationship primaryRelationship = primaryEntity.Relationships
                                               .FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey == false);

            if (primaryRelationship == null)
            {
                primaryRelationship = new Relationship {
                    RelationshipName = relationshipName
                };
                primaryEntity.Relationships.Add(primaryRelationship);
            }

            primaryRelationship.IsMapped     = false;
            primaryRelationship.IsForeignKey = false;

            primaryRelationship.PrimaryEntity     = foreignEntity;
            primaryRelationship.PrimaryProperties = new PropertyCollection(foreignMembers);

            primaryRelationship.Entity     = primaryEntity;
            primaryRelationship.Properties = new PropertyCollection(primaryMembers);

            bool isOneToOne = IsOneToOne(tableKeySchema, foreignRelationship);

            if (isOneToOne)
            {
                primaryRelationship.Cardinality = primaryMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;
            }
            else
            {
                primaryRelationship.Cardinality = Cardinality.Many;
            }

            string primaryPropertyName = prefix + foreignName;

            if (!isOneToOne)
            {
                primaryPropertyName = RelationshipName(primaryPropertyName);
            }

            primaryPropertyName = ToPropertyName(primaryEntity.EntityClass, primaryPropertyName);
            primaryPropertyName = _namer.UniqueName(primaryEntity.EntityClass, primaryPropertyName);

            primaryRelationship.PropertyName = primaryPropertyName;

            foreignRelationship.PrimaryPropertyName = primaryRelationship.PropertyName;
            foreignRelationship.PrimaryCardinality  = primaryRelationship.Cardinality;

            primaryRelationship.PrimaryPropertyName = foreignRelationship.PropertyName;
            primaryRelationship.PrimaryCardinality  = foreignRelationship.Cardinality;

            foreignRelationship.IsProcessed = true;
            primaryRelationship.IsProcessed = true;
        }
Exemple #16
0
 protected override DropForeignKeyOperation Drop(DatabaseForeignKey foreignKey)
 => AdDOptimizedAnnotation(base.Drop(foreignKey), foreignKey.Table);
Exemple #17
0
        private void GetForeignKeys()
        {
            var command = _connection.CreateCommand();

            command.CommandText = @"SELECT
    schema_name(f.schema_id) AS [schema_name],
    object_name(f.parent_object_id) AS table_name,
    f.name AS foreign_key_name,
    object_schema_name(f.referenced_object_id) AS principal_table_schema_name,
    object_name(f.referenced_object_id) AS principal_table_name,
    col_name(fc.parent_object_id, fc.parent_column_id) AS constraint_column_name,
    col_name(fc.referenced_object_id, fc.referenced_column_id) AS referenced_column_name,
    is_disabled,
    delete_referential_action_desc,
    update_referential_action_desc,
    fc.constraint_column_id
FROM sys.foreign_keys AS f
    INNER JOIN sys.foreign_key_columns AS fc ON f.object_id = fc.constraint_object_id
ORDER BY schema_name(f.schema_id), object_name(f.parent_object_id), f.name, fc.constraint_column_id";
            using (var reader = command.ExecuteReader())
            {
                var lastFkName                = string.Empty;
                var lastFkSchemaName          = string.Empty;
                var lastFkTableName           = string.Empty;
                DatabaseForeignKey foreignKey = null;
                while (reader.Read())
                {
                    var schemaName = reader.GetValueOrDefault <string>("schema_name");
                    var tableName  = reader.GetValueOrDefault <string>("table_name");
                    var fkName     = reader.GetValueOrDefault <string>("foreign_key_name");
                    var principalTableSchemaName = reader.GetValueOrDefault <string>("principal_table_schema_name");
                    var principalTableName       = reader.GetValueOrDefault <string>("principal_table_name");
                    var fromColumnName           = reader.GetValueOrDefault <string>("constraint_column_name");
                    var toColumnName             = reader.GetValueOrDefault <string>("referenced_column_name");
                    var updateAction             = reader.GetValueOrDefault <string>("update_referential_action_desc");
                    var deleteAction             = reader.GetValueOrDefault <string>("delete_referential_action_desc");
                    var ordinal = reader.GetValueOrDefault <int>("constraint_column_id");

                    Logger.ForeignKeyColumnFound(
                        DisplayName(schemaName, tableName), fkName, DisplayName(principalTableSchemaName, principalTableName),
                        fromColumnName, toColumnName, updateAction, deleteAction, ordinal);

                    if (string.IsNullOrEmpty(fkName))
                    {
                        Logger.ForeignKeyNotNamedWarning(DisplayName(schemaName, tableName));
                        continue;
                    }

                    if (!_tableSelectionSet.Allows(schemaName, tableName))
                    {
                        Logger.ForeignKeyColumnMissingWarning(fromColumnName, fkName, DisplayName(schemaName, tableName));
                        continue;
                    }

                    if (foreignKey == null ||
                        lastFkSchemaName != schemaName ||
                        lastFkTableName != tableName ||
                        lastFkName != fkName)
                    {
                        lastFkName       = fkName;
                        lastFkSchemaName = schemaName;
                        lastFkTableName  = tableName;
                        var table = _tables[SchemaQualifiedKey(tableName, schemaName)];

                        DatabaseTable principalTable = null;
                        if (!string.IsNullOrEmpty(principalTableSchemaName) &&
                            !string.IsNullOrEmpty(principalTableName))
                        {
                            _tables.TryGetValue(SchemaQualifiedKey(principalTableName, principalTableSchemaName), out principalTable);
                        }

                        if (principalTable == null)
                        {
                            Logger.ForeignKeyReferencesMissingPrincipalTableWarning(
                                fkName, DisplayName(schemaName, tableName), DisplayName(principalTableSchemaName, principalTableName));
                        }

                        foreignKey = new DatabaseForeignKey
                        {
                            Name           = fkName,
                            Table          = table,
                            PrincipalTable = principalTable,
                            OnDelete       = ConvertToReferentialAction(deleteAction)
                        };

                        table.ForeignKeys.Add(foreignKey);
                    }

                    DatabaseColumn fromColumn;
                    if ((fromColumn = FindColumnForForeignKey(fromColumnName, foreignKey.Table, fkName)) != null)
                    {
                        foreignKey.Columns.Add(fromColumn);
                    }

                    if (foreignKey.PrincipalTable != null)
                    {
                        DatabaseColumn toColumn;
                        if ((toColumn = FindColumnForForeignKey(toColumnName, foreignKey.PrincipalTable, fkName)) != null)
                        {
                            foreignKey.PrincipalColumns.Add(toColumn);
                        }
                    }
                }
            }
        }
Exemple #18
0
        public void GenerateRelationships(int expectedRelationships, bool processRelationships)
        {
            var generatorOptions = new GeneratorOptions();

            generatorOptions.Database.ProcessRelationships = processRelationships;

            var databaseModel = new DatabaseModel
            {
                DatabaseName  = "TestDatabase",
                DefaultSchema = "dbo"
            };

            var principalTable = new DatabaseTable
            {
                Database = databaseModel,
                Name     = "PrincipalTable",
                Schema   = "dbo",
            };

            var idPrincipalTable = new DatabaseColumn
            {
                Table      = principalTable,
                Name       = "Id",
                IsNullable = false,
                StoreType  = "int"
            };

            principalTable.Columns.Add(idPrincipalTable);

            var table = new DatabaseTable
            {
                Database = databaseModel,
                Name     = "RelatedTable",
                Schema   = "dbo",
            };

            var idTable = new DatabaseColumn
            {
                Table      = table,
                Name       = "Id",
                IsNullable = false,
                StoreType  = "int"
            };


            table.Columns.Add(idTable);

            var fk = new DatabaseForeignKey
            {
                PrincipalTable = principalTable,
                Table          = table
            };


            fk.PrincipalColumns.Add(idPrincipalTable);
            fk.Columns.Add(idTable);
            table.ForeignKeys.Add(fk);

            databaseModel.Tables.Add(principalTable);
            databaseModel.Tables.Add(table);

            var generator = new ModelGenerator(NullLoggerFactory.Instance);

            var typeMappingSource = CreateTypeMappingSource();
            var entityContext     = generator.Generate(generatorOptions, databaseModel, typeMappingSource);

            var principalEntity = entityContext.Entities[0];
            var entity          = entityContext.Entities[1];

            principalEntity.Relationships.Count.Should().Be(expectedRelationships);
            entity.Relationships.Count.Should().Be(expectedRelationships);
        }
        private void GetForeignKeys(
            DbConnection connection,
            string tableFilter,
            DatabaseModel databaseModel)
        {
            using (var command = connection.CreateCommand())
            {
                command.CommandText = new StringBuilder()
                                      .AppendLine("SELECT t.tablespace_name,")
                                      .AppendLine("     x.table_name,")
                                      .AppendLine("     x.column_name,")
                                      .AppendLine("     c.table_name principal_table_name,")
                                      .AppendLine("     r.delete_rule,")
                                      .AppendLine("     r.constraint_name,")
                                      .AppendLine("     c.column_name principal_column_name")
                                      .AppendLine("FROM all_cons_columns x,")
                                      .AppendLine("     all_cons_columns c,")
                                      .AppendLine("     all_constraints r,")
                                      .AppendLine("     user_tables t")
                                      .AppendLine(tableFilter)
                                      .AppendLine("  AND x.constraint_name = r.constraint_name")
                                      .AppendLine("  AND t.table_name = x.table_name")
                                      .AppendLine("  AND c.constraint_name = r.r_constraint_name")
                                      .AppendLine("  AND c.owner = r.r_owner")
                                      .AppendLine("  AND r.constraint_type = 'R'")
                                      .ToString();

                using (var reader = command.ExecuteReader())
                {
                    var tableForeignKeyGroups = reader.Cast <DbDataRecord>()
                                                .GroupBy(
                        ddr => (tableSchema: ddr.GetValueOrDefault <string>("tablespace_name"),
                                tableName: ddr.GetValueOrDefault <string>("table_name")));

                    foreach (var tableForeignKeyGroup in tableForeignKeyGroups)
                    {
                        var tableSchema = tableForeignKeyGroup.Key.tableSchema;
                        var tableName   = tableForeignKeyGroup.Key.tableName;

                        var table = databaseModel.Tables.Single(t => t.Schema == tableSchema && t.Name == tableName);

                        var foreignKeyGroups = tableForeignKeyGroup
                                               .GroupBy(
                            c => (Name: c.GetValueOrDefault <string>("constraint_name"),
                                  PrincipalTableSchema: c.GetValueOrDefault <string>("tablespace_name"),
                                  PrincipalTableName: c.GetValueOrDefault <string>("principal_table_name"),
                                  OnDeleteAction: c.GetValueOrDefault <string>("delete_rule")));

                        foreach (var foreignKeyGroup in foreignKeyGroups)
                        {
                            var fkName = foreignKeyGroup.Key.Name;
                            var principalTableSchema = foreignKeyGroup.Key.PrincipalTableSchema;
                            var principalTableName   = foreignKeyGroup.Key.PrincipalTableName;
                            var onDeleteAction       = foreignKeyGroup.Key.OnDeleteAction;

                            _logger.ForeignKeyFound(
                                fkName,
                                DisplayName(table.Schema, table.Name),
                                DisplayName(principalTableSchema, principalTableName),
                                onDeleteAction);

                            var principalTable = databaseModel.Tables.FirstOrDefault(
                                t => t.Schema == principalTableSchema &&
                                t.Name == principalTableName)
                                                 ?? databaseModel.Tables.FirstOrDefault(
                                t => t.Schema.Equals(principalTableSchema, StringComparison.OrdinalIgnoreCase) &&
                                t.Name.Equals(principalTableName, StringComparison.OrdinalIgnoreCase));

                            if (principalTable == null)
                            {
                                _logger.ForeignKeyReferencesMissingPrincipalTableWarning(
                                    fkName,
                                    DisplayName(table.Schema, table.Name),
                                    DisplayName(principalTableSchema, principalTableName));

                                continue;
                            }

                            var foreignKey = new DatabaseForeignKey
                            {
                                Name           = fkName,
                                Table          = table,
                                PrincipalTable = principalTable,
                                OnDelete       = ConvertToReferentialAction(onDeleteAction)
                            };

                            var invalid = false;

                            foreach (var dataRecord in foreignKeyGroup)
                            {
                                var columnName = dataRecord.GetValueOrDefault <string>("column_name");
                                var column     = table.Columns.FirstOrDefault(c => c.Name == columnName)
                                                 ?? table.Columns.FirstOrDefault(c => c.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase));

                                var principalColumnName = dataRecord.GetValueOrDefault <string>("principal_column_name");
                                var principalColumn     = foreignKey.PrincipalTable.Columns.FirstOrDefault(c => c.Name == principalColumnName)
                                                          ?? foreignKey.PrincipalTable.Columns.FirstOrDefault(c => c.Name.Equals(principalColumnName, StringComparison.OrdinalIgnoreCase));
                                if (principalColumn == null)
                                {
                                    invalid = true;
                                    _logger.ForeignKeyPrincipalColumnMissingWarning(
                                        fkName,
                                        DisplayName(table.Schema, table.Name),
                                        principalColumnName,
                                        DisplayName(principalTableSchema, principalTableName));
                                    break;
                                }

                                foreignKey.Columns.Add(column);
                                foreignKey.PrincipalColumns.Add(principalColumn);
                            }

                            if (!invalid)
                            {
                                table.ForeignKeys.Add(foreignKey);
                            }
                        }
                    }
                }
            }
        }
 protected override MigrationOperation Drop(DatabaseForeignKey foreignKey)
 => AddSqlServerSpecificAnnotations(base.Drop(foreignKey), foreignKey.Table);
Exemple #21
0
        private void GetForeignKeys()
        {
            var command = _connection.CreateCommand();
            var dbName  = _connection.Database;

            command.CommandText = $@"SELECT 
  kc.constraint_name, 
  kc.table_schema, 
  kc.table_name, 
  kc.column_name, 
  kc.referenced_table_schema, 
  kc.referenced_table_name, 
  kc.referenced_column_name, 
  kc.ordinal_position, 
  rc.update_rule, 
  rc.delete_rule 
FROM information_schema.key_column_usage as kc 
INNER JOIN information_schema.referential_constraints as rc 
ON kc.constraint_catalog = rc.constraint_catalog 
  AND kc.constraint_schema = rc.constraint_schema 
  AND kc.constraint_name = rc.constraint_name 
WHERE kc.referenced_table_name IS NOT NULL 
  AND LOWER(kc.table_schema) IN ({_schemaList.ToLowerInvariant()})
  AND kc.table_name NOT LIKE '{HistoryRepository.DefaultTableName}'";

            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    DatabaseForeignKey foreignKey = null;
                    var tableSchema           = reader.GetValueOrDefault <string>("table_schema");
                    var constraintName        = reader.GetValueOrDefault <string>("constraint_name");
                    var tableName             = reader.GetValueOrDefault <string>("table_name");
                    var columnName            = reader.GetValueOrDefault <string>("column_name");
                    var referencedTableSchema = reader.GetValueOrDefault <string>("referenced_table_schema");
                    var referencedTableName   = reader.GetValueOrDefault <string>("referenced_table_name");
                    var referencedColumnName  = reader.GetValueOrDefault <string>("referenced_column_name");
                    var updateRule            = reader.GetValueOrDefault <string>("update_rule");
                    var deleteRule            = reader.GetValueOrDefault <string>("delete_rule");
                    var ordinal = reader.GetInt32("ordinal_position");

                    if (string.IsNullOrEmpty(constraintName))
                    {
                        Logger.LogWarning("Foreign key must be named warning", tableSchema, tableName);
                        continue;
                    }

                    if (!_tableSelectionSet.Allows(tableSchema, tableName))
                    {
                        Logger.LogDebug("Foreign key column skipped", new string[] { referencedColumnName, constraintName, tableSchema, tableName });
                        continue;
                    }
                    var table = _tables[TableKey(tableName, tableSchema)];

                    DatabaseTable principalTable = null;
                    if (!string.IsNullOrEmpty(tableSchema) &&
                        !string.IsNullOrEmpty(referencedTableName))
                    {
                        _tables.TryGetValue(TableKey(referencedTableName, tableSchema), out principalTable);
                    }

                    if (principalTable == null)
                    {
                        Logger.LogDebug("Foreign key references missing table", new string[] { constraintName, tableName, tableSchema });
                    }

                    foreignKey = new DatabaseForeignKey
                    {
                        Name           = constraintName,
                        Table          = table,
                        PrincipalTable = principalTable,
                        OnDelete       = ConvertToReferentialAction(deleteRule)
                    };

                    table.ForeignKeys.Add(foreignKey);

                    DatabaseColumn fromColumn = FindColumnForForeignKey(columnName, foreignKey.Table, constraintName);
                    if (fromColumn != null)
                    {
                        foreignKey.Columns.Add(fromColumn);
                    }

                    if (foreignKey.PrincipalTable != null)
                    {
                        DatabaseColumn toColumn = FindColumnForForeignKey(referencedColumnName, foreignKey.PrincipalTable, constraintName);
                        if (toColumn != null)
                        {
                            foreignKey.PrincipalColumns.Add(toColumn);
                        }
                    }
                }
            }
        }
Exemple #22
0
        void GetConstraints(
            NpgsqlConnection connection,
            IReadOnlyList <DatabaseTable> tables,
            string tableFilter,
            out List <uint> constraintIndexes)
        {
            constraintIndexes = new List <uint>();

            var getConstraints = @"
SELECT
    ns.nspname, cls.relname, conname, contype, conkey, conindid,
    frnns.nspname AS fr_nspname, frncls.relname AS fr_relname, confkey, confdeltype
FROM pg_class AS cls
JOIN pg_namespace AS ns ON ns.oid = cls.relnamespace
JOIN pg_constraint as con ON con.conrelid = cls.oid
LEFT OUTER JOIN pg_class AS frncls ON frncls.oid = con.confrelid
LEFT OUTER JOIN pg_namespace as frnns ON frnns.oid = frncls.relnamespace
WHERE
    cls.relkind = 'r' AND
    ns.nspname NOT IN ('pg_catalog', 'information_schema')
AND
    con.contype IN ('p', 'f', 'u')
" + tableFilter;

            var command = connection.CreateCommand();

            command.CommandText = getConstraints;

            using (var reader = command.ExecuteReader())
            {
                var tableGroups = reader.Cast <DbDataRecord>()
                                  .GroupBy(
                    ddr => (tableSchema: ddr.GetValueOrDefault <string>("nspname"),
                            tableName: ddr.GetValueOrDefault <string>("relname")));

                foreach (var tableGroup in tableGroups)
                {
                    var tableSchema = tableGroup.Key.tableSchema;
                    var tableName   = tableGroup.Key.tableName;

                    var table = tables.Single(t => t.Schema == tableSchema && t.Name == tableName);

                    // Primary keys
                    foreach (var primaryKeyRecord in tableGroup
                             .Where(ddr => ddr.GetValueOrDefault <char>("contype") == 'p'))
                    {
                        var primaryKey = new DatabasePrimaryKey
                        {
                            Table = table,
                            Name  = primaryKeyRecord.GetValueOrDefault <string>("conname")
                        };

                        var pkColumnIndices = primaryKeyRecord.GetValueOrDefault <short[]>("conkey");
                        foreach (var pkColumnIndex in pkColumnIndices)
                        {
                            primaryKey.Columns.Add(table.Columns[pkColumnIndex - 1]);
                        }
                        table.PrimaryKey = primaryKey;
                    }

                    // Foreign keys
                    foreach (var foreignKeyRecord in tableGroup
                             .Where(ddr => ddr.GetValueOrDefault <char>("contype") == 'f'))
                    {
                        var fkName = foreignKeyRecord.GetValueOrDefault <string>("conname");
                        var principalTableSchema = foreignKeyRecord.GetValueOrDefault <string>("fr_nspname");
                        var principalTableName   = foreignKeyRecord.GetValueOrDefault <string>("fr_relname");
                        var onDeleteAction       = foreignKeyRecord.GetValueOrDefault <char>("confdeltype");

                        var principalTable = tables.FirstOrDefault(
                            t => t.Schema == principalTableSchema &&
                            t.Name == principalTableName)
                                             ?? tables.FirstOrDefault(
                            t => t.Schema.Equals(principalTableSchema, StringComparison.OrdinalIgnoreCase) &&
                            t.Name.Equals(principalTableName, StringComparison.OrdinalIgnoreCase));

                        if (principalTable == null)
                        {
                            _logger.ForeignKeyReferencesMissingPrincipalTableWarning(
                                fkName,
                                DisplayName(table.Schema, table.Name),
                                DisplayName(principalTableSchema, principalTableName));

                            continue;
                        }

                        var foreignKey = new DatabaseForeignKey
                        {
                            Name           = fkName,
                            Table          = table,
                            PrincipalTable = principalTable,
                            OnDelete       = ConvertToReferentialAction(onDeleteAction)
                        };

                        var columnIndices          = foreignKeyRecord.GetValueOrDefault <short[]>("conkey");
                        var principalColumnIndices = foreignKeyRecord.GetValueOrDefault <short[]>("confkey");
                        if (columnIndices.Length != principalColumnIndices.Length)
                        {
                            throw new Exception("Got varying lengths for column and principal column indices");
                        }

                        var principalColumns = (List <DatabaseColumn>)principalTable.Columns;

                        for (var i = 0; i < columnIndices.Length; i++)
                        {
                            foreignKey.Columns.Add(table.Columns[columnIndices[i] - 1]);
                            foreignKey.PrincipalColumns.Add(principalColumns[principalColumnIndices[i] - 1]);
                        }

                        table.ForeignKeys.Add(foreignKey);
                    }

                    // Unique constraints
                    foreach (var record in tableGroup
                             .Where(ddr => ddr.GetValueOrDefault <char>("contype") == 'u')
                             .ToArray())
                    {
                        var name = record.GetValueOrDefault <string>("conname");

                        _logger.UniqueConstraintFound(name, DisplayName(tableSchema, tableName));

                        var uniqueConstraint = new DatabaseUniqueConstraint
                        {
                            Table = table,
                            Name  = name
                        };

                        var columnIndices = record.GetValueOrDefault <short[]>("conkey");
                        foreach (var t in columnIndices)
                        {
                            uniqueConstraint.Columns.Add(table.Columns[t - 1]);
                        }

                        table.UniqueConstraints.Add(uniqueConstraint);
                        constraintIndexes.Add(record.GetValueOrDefault <uint>("conindid"));
                    }
                }
            }
        }
        private void GetForeignKeys()
        {
            var command = _connection.CreateCommand();

            command.CommandText = @"SELECT 
                KCU1.CONSTRAINT_NAME AS FK_CONSTRAINT_NAME,
                --KCU1.TABLE_NAME + '_' + KCU1.CONSTRAINT_NAME AS FK_CONSTRAINT_NAME,
                NULL AS [SCHEMA_NAME],
                KCU1.TABLE_NAME AS FK_TABLE_NAME,  
                NULL AS [UQ_SCHEMA_NAME],
                KCU2.TABLE_NAME AS UQ_TABLE_NAME, 
                KCU1.COLUMN_NAME AS FK_COLUMN_NAME, 
                KCU2.COLUMN_NAME AS UQ_COLUMN_NAME, 
                0 AS [IS_DISABLED],
                RC.DELETE_RULE, 
                RC.UPDATE_RULE,
                KCU1.ORDINAL_POSITION
                FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC 
                JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1 ON KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 
                AND KCU1.TABLE_NAME = RC.CONSTRAINT_TABLE_NAME 
                JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 ON  KCU2.CONSTRAINT_NAME =  RC.UNIQUE_CONSTRAINT_NAME 
                    AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION 
                    AND KCU2.TABLE_NAME = RC.UNIQUE_CONSTRAINT_TABLE_NAME 
                ORDER BY FK_TABLE_NAME, FK_CONSTRAINT_NAME, KCU1.ORDINAL_POSITION;";
            using (var reader = command.ExecuteReader())
            {
                var lastFkName            = "";
                DatabaseForeignKey fkInfo = null;
                while (reader.Read())
                {
                    var fkName             = reader.GetValueOrDefault <string>("FK_CONSTRAINT_NAME");
                    var tableName          = reader.GetValueOrDefault <string>("FK_TABLE_NAME");
                    var principalTableName = reader.GetValueOrDefault <string>("UQ_TABLE_NAME");
                    var fromColumnName     = reader.GetValueOrDefault <string>("FK_COLUMN_NAME");
                    var toColumnName       = reader.GetValueOrDefault <string>("UQ_COLUMN_NAME");

                    if (!_tableSelectionSet.Allows(tableName))
                    {
                        continue;
                    }

                    if ((fkInfo == null) ||
                        (lastFkName != fkName))
                    {
                        lastFkName = fkName;
                        var           table = _tables[TableKey(tableName)];
                        DatabaseTable principalTable;
                        _tables.TryGetValue(TableKey(principalTableName), out principalTable);

                        fkInfo = new DatabaseForeignKey
                        {
                            Name           = fkName,
                            Table          = table,
                            PrincipalTable = principalTable,
                            OnDelete       = ConvertToReferentialAction(reader.GetValueOrDefault <string>("DELETE_RULE"))
                        };

                        table.ForeignKeys.Add(fkInfo);
                    }

                    DatabaseColumn fromColumn;
                    if ((fromColumn = FindColumnForForeignKey(fromColumnName, fkInfo.Table, fkName)) != null)
                    {
                        fkInfo.Columns.Add(fromColumn);
                    }

                    if (fkInfo.PrincipalTable != null)
                    {
                        DatabaseColumn toColumn;
                        if ((toColumn = FindColumnForForeignKey(toColumnName, fkInfo.PrincipalTable, fkName)) != null)
                        {
                            fkInfo.PrincipalColumns.Add(toColumn);
                        }
                    }
                }
            }
        }
Exemple #24
0
        private void GetForeignKeys(DbConnection connection, IReadOnlyList <DatabaseTable> tables)
        {
            using var command = connection.CreateCommand();
            var commandText =
                "SELECT * FROM ("
                + "SELECT FK.TABLE_CATALOG AS FK_CATALOG, FK.TABLE_SCHEMA AS FK_SCHEMA, FK.TABLE_NAME AS FK_TABLE, FK.CONSTRAINT_NAME, FK_COLS.COLUMN_NAME AS FK_COL_NAME, PK_COLS.TABLE_NAME AS PK_TABLE, PK_COLS.COLUMN_NAME AS PK_COL_NAME, FK_COLS.POSITION_IN_UNIQUE_CONSTRAINT AS ORDINAL_POSITION "
                + "from INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK "
                + "inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON "
                + "    FK.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG AND "
                + "    FK.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA AND "
                + "    FK.CONSTRAINT_NAME = RC.CONSTRAINT_NAME AND "
                + "    FK.CONSTRAINT_TYPE = 'FOREIGN KEY' "
                + "inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE FK_COLS ON "
                + "    FK.CONSTRAINT_CATALOG = FK_COLS.CONSTRAINT_CATALOG AND "
                + "    FK.CONSTRAINT_SCHEMA = FK_COLS.CONSTRAINT_SCHEMA AND "
                + "    FK.CONSTRAINT_NAME = FK_COLS.CONSTRAINT_NAME "
                + "inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE PK_COLS ON "
                + "    RC.UNIQUE_CONSTRAINT_CATALOG = PK_COLS.CONSTRAINT_CATALOG AND "
                + "    RC.UNIQUE_CONSTRAINT_SCHEMA = PK_COLS.CONSTRAINT_SCHEMA AND "
                + "    RC.UNIQUE_CONSTRAINT_NAME = PK_COLS.CONSTRAINT_NAME AND "
                + "    FK_COLS.POSITION_IN_UNIQUE_CONSTRAINT = PK_COLS.ORDINAL_POSITION "
                + "where FK.CONSTRAINT_CATALOG = '' AND FK.CONSTRAINT_SCHEMA = '' "

                + "UNION ALL "

                + "SELECT CHILD.TABLE_CATALOG AS FK_CATALOG, CHILD.TABLE_SCHEMA AS FK_SCHEMA, CHILD.TABLE_NAME AS FK_TABLE, PK_PARENT.CONSTRAINT_NAME AS CONSTRAINT_NAME, FK_COLS.COLUMN_NAME AS FK_COL_NAME, PARENT.TABLE_NAME AS PK_TABLE, FK_COLS.COLUMN_NAME AS PK_COL_NAME, FK_COLS.ORDINAL_POSITION "
                + "FROM INFORMATION_SCHEMA.TABLES CHILD "
                + "INNER JOIN INFORMATION_SCHEMA.TABLES PARENT ON "
                + "    CHILD.TABLE_CATALOG = PARENT.TABLE_CATALOG AND "
                + "    CHILD.TABLE_SCHEMA = PARENT.TABLE_SCHEMA AND "
                + "    CHILD.PARENT_TABLE_NAME = PARENT.TABLE_NAME "
                + "INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK_CHILD ON "
                + "    CHILD.TABLE_CATALOG = PK_CHILD.TABLE_CATALOG AND "
                + "    CHILD.TABLE_SCHEMA = PK_CHILD.TABLE_SCHEMA AND "
                + "    CHILD.TABLE_NAME = PK_CHILD.TABLE_NAME AND "
                + "    PK_CHILD.CONSTRAINT_TYPE = 'PRIMARY KEY' "
                + "INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK_PARENT ON "
                + "    PARENT.TABLE_CATALOG = PK_PARENT.TABLE_CATALOG AND "
                + "    PARENT.TABLE_SCHEMA = PK_PARENT.TABLE_SCHEMA AND "
                + "    PARENT.TABLE_NAME = PK_PARENT.TABLE_NAME AND "
                + "    PK_PARENT.CONSTRAINT_TYPE = 'PRIMARY KEY' "
                + "INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE FK_COLS ON "
                + "    PK_PARENT.CONSTRAINT_CATALOG = FK_COLS.CONSTRAINT_CATALOG AND "
                + "    PK_PARENT.CONSTRAINT_SCHEMA = FK_COLS.CONSTRAINT_SCHEMA AND "
                + "    PK_PARENT.CONSTRAINT_NAME = FK_COLS.CONSTRAINT_NAME "
                + "WHERE CHILD.TABLE_CATALOG = '' AND CHILD.TABLE_SCHEMA = '' "

                + ") FK "
                + "ORDER BY FK_CATALOG, FK_SCHEMA, FK_TABLE, CONSTRAINT_NAME, ORDINAL_POSITION ";

            command.CommandText = commandText;

            using var reader = command.ExecuteReader();
            var tableFkGroups = reader.Cast <DbDataRecord>()
                                .GroupBy(ddr => (
                                             FkTable: ddr.GetValueOrDefault <string>("FK_TABLE"),
                                             PkTable: ddr.GetValueOrDefault <string>("PK_TABLE"),
                                             Name: ddr.GetValueOrDefault <string>("CONSTRAINT_NAME")
                                             ));

            foreach (var tableFkGroup in tableFkGroups)
            {
                var fkTableName = tableFkGroup.Key.FkTable;
                var fkTable     = tables.Single(t => t.Name == fkTableName);
                var pkTableName = tableFkGroup.Key.PkTable;
                var pkTable     = tables.Single(t => t.Name == pkTableName);
                var fk          = new DatabaseForeignKey {
                    Name = tableFkGroup.Key.Name, Table = fkTable, PrincipalTable = pkTable, OnDelete = ReferentialAction.Restrict
                };

                foreach (var col in tableFkGroup)
                {
                    var fkCol = fkTable.Columns.FirstOrDefault(c => c.Name == col.GetValueOrDefault <string>("FK_COL_NAME"));
                    fk.Columns.Add(fkCol);
                    var pkCol = pkTable.Columns.FirstOrDefault(c => c.Name == col.GetValueOrDefault <string>("PK_COL_NAME"));
                    fk.PrincipalColumns.Add(pkCol);
                }

                fkTable.ForeignKeys.Add(fk);
            }
        }
Exemple #25
0
 protected override MigrationOperation Drop(DatabaseForeignKey foreignKey)
 => AddMemoryOptimizedAnnotation(base.Drop(foreignKey), foreignKey.Table);
Exemple #26
0
        private void GetRelations(DbConnection connection, IReadOnlyList <DatabaseTable> tables)
        {
            var relationTable = new DataTable();

            using (var command = connection.CreateCommand())
            {
                command.CommandText = $@"SELECT * FROM `INFORMATION_SCHEMA.RELATIONS` ORDER BY RELATION_NAME, REFERENCING_TABLE_NAME, PRINCIPAL_TABLE_NAME";

                using var reader = command.ExecuteReader();
                relationTable.Load(reader);
            }

            var relationColumnsTable = new DataTable();

            using (var command = connection.CreateCommand())
            {
                command.CommandText = "SELECT * FROM `INFORMATION_SCHEMA.RELATION_COLUMNS` ORDER BY RELATION_NAME, REFERENCING_COLUMN_NAME, PRINCIPAL_COLUMN_NAME";
                using var reader    = command.ExecuteReader();
                relationColumnsTable.Load(reader);
            }

            var groupedRelationColumns = relationColumnsTable.Rows.Cast <DataRow>()
                                         .GroupBy(r => r.GetValueOrDefault <string>("RELATION_NAME"))
                                         .ToList();

            foreach (DataRow relationRow in relationTable.Rows)
            {
                var relationName         = relationRow.GetValueOrDefault <string>("RELATION_NAME");
                var referencingTableName = relationRow.GetValueOrDefault <string>("REFERENCING_TABLE_NAME");
                var principalTableName   = relationRow.GetValueOrDefault <string>("PRINCIPAL_TABLE_NAME");
                var relationType         = relationRow.GetValueOrDefault <string>("RELATION_TYPE");
                var onDelete             = relationRow.GetValueOrDefault <string>("ON_DELETE");
                var onUpdate             = relationRow.GetValueOrDefault <string>("ON_UPDATE");
                var enforced             = relationRow.GetValueOrDefault <bool>("IS_ENFORCED", true);
                var inherited            = relationRow.GetValueOrDefault <bool>("IS_INHERITED", true);

                var referencingTable = tables.FirstOrDefault(t => string.Equals(t.Name, referencingTableName)) ??
                                       tables.FirstOrDefault(t => string.Equals(t.Name, referencingTableName, StringComparison.OrdinalIgnoreCase));
                if (referencingTable != null)
                {
                    var relationColumns = groupedRelationColumns.FirstOrDefault(g => g.Key == relationName);
                    if (relationColumns?.Any() ?? false)
                    {
                        _logger.ForeignKeyFound(
                            relationName,
                            referencingTableName,
                            principalTableName,
                            onDelete);

                        var principalTable = tables.FirstOrDefault(t => string.Equals(t.Name, principalTableName)) ??
                                             tables.FirstOrDefault(t => string.Equals(t.Name, principalTableName, StringComparison.OrdinalIgnoreCase));
                        if (principalTable == null)
                        {
                            _logger.ForeignKeyReferencesMissingPrincipalTableWarning(
                                relationName,
                                referencingTableName,
                                principalTableName);
                            continue;
                        }

                        var foreignKey = new DatabaseForeignKey
                        {
                            Name           = relationName,
                            Table          = referencingTable,
                            PrincipalTable = principalTable,
                            OnDelete       = ConvertToReferentialAction(onDelete),
                        };

                        var invalid = false;
                        foreach (var relationColumn in relationColumns)
                        {
                            var referencingColumnName = relationColumn.GetValueOrDefault <string>("REFERENCING_COLUMN_NAME");
                            var referencingColumn     = referencingTable.Columns.FirstOrDefault(c => c.Name == referencingColumnName) ??
                                                        referencingTable.Columns.FirstOrDefault(c => string.Equals(c.Name, referencingColumnName, StringComparison.OrdinalIgnoreCase));
                            Debug.Assert(referencingColumn != null, "referencingColumn is null.");

                            var principalColumnName = relationColumn.GetValueOrDefault <string>("PRINCIPAL_COLUMN_NAME");
                            var principalColumn     = principalTable.Columns.FirstOrDefault(c => c.Name == principalColumnName) ??
                                                      principalTable.Columns.FirstOrDefault(c => string.Equals(c.Name, principalColumnName, StringComparison.OrdinalIgnoreCase));
                            if (principalColumn == null)
                            {
                                invalid = true;
                                _logger.ForeignKeyPrincipalColumnMissingWarning(
                                    relationName,
                                    referencingTableName,
                                    principalColumnName,
                                    principalTableName);
                                break;
                            }

                            foreignKey.Columns.Add(referencingColumn);
                            foreignKey.PrincipalColumns.Add(principalColumn);
                        }

                        if (invalid)
                        {
                            continue;
                        }

                        if (foreignKey.Columns.SequenceEqual(foreignKey.PrincipalColumns))
                        {
                            _logger.ReflexiveConstraintIgnored(
                                foreignKey.Name,
                                referencingTableName);
                        }
                        else
                        {
                            referencingTable.ForeignKeys.Add(foreignKey);
                        }
                    }
                }
            }
        }
        /// <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 IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder modelBuilder, [NotNull] DatabaseForeignKey foreignKey)
        {
            Check.NotNull(modelBuilder, nameof(modelBuilder));
            Check.NotNull(foreignKey, nameof(foreignKey));

            if (foreignKey.PrincipalTable == null)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPrincipalTableNotFound(foreignKey.DisplayName()));
                return(null);
            }

            if (foreignKey.Table == null)
            {
                return(null);
            }

            var dependentEntityType = modelBuilder.Model.FindEntityType(GetEntityTypeName(foreignKey.Table));

            if (dependentEntityType == null)
            {
                return(null);
            }

            var unmappedDependentColumns = foreignKey.Columns
                                           .Where(c => _unmappedColumns.Contains(c))
                                           .Select(c => c.Name)
                                           .ToList();

            if (unmappedDependentColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName(),
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedDependentColumns)));
                return(null);
            }

            var dependentProperties = foreignKey.Columns
                                      .Select(GetPropertyName)
                                      .Select(name => dependentEntityType.FindProperty(name))
                                      .ToList()
                                      .AsReadOnly();

            var principalEntityType = modelBuilder.Model.FindEntityType(GetEntityTypeName(foreignKey.PrincipalTable));

            if (principalEntityType == null)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPrincipalTableScaffoldingError(
                        foreignKey.DisplayName(),
                        foreignKey.PrincipalTable.DisplayName()));
                return(null);
            }

            var unmappedPrincipalColumns = foreignKey.PrincipalColumns
                                           .Where(pc => principalEntityType.FindProperty(GetPropertyName(pc)) == null)
                                           .Select(pc => pc.Name)
                                           .ToList();

            if (unmappedPrincipalColumns.Count > 0)
            {
                _reporter.WriteWarning(
                    DesignStrings.ForeignKeyScaffoldErrorPropertyNotFound(
                        foreignKey.DisplayName(),
                        string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, unmappedPrincipalColumns)));
                return(null);
            }

            var principalPropertiesMap = foreignKey.PrincipalColumns
                                         .Select(
                fc => (property: principalEntityType.FindProperty(GetPropertyName(fc)), column: fc)).ToList();
            var principalProperties = principalPropertiesMap
                                      .Select(tuple => tuple.property)
                                      .ToList();

            var principalKey = principalEntityType.FindKey(principalProperties);

            if (principalKey == null)
            {
                var index = principalEntityType.GetIndexes()
                            .Where(i => i.Properties.SequenceEqual(principalProperties) && i.IsUnique)
                            .FirstOrDefault();
                if (index != null)
                {
                    // ensure all principal properties are non-nullable even if the columns
                    // are nullable on the database. EF's concept of a key requires this.
                    var nullablePrincipalProperties =
                        principalPropertiesMap.Where(tuple => tuple.property.IsNullable).ToList();
                    if (nullablePrincipalProperties.Count > 0)
                    {
                        _reporter.WriteWarning(
                            DesignStrings.ForeignKeyPrincipalEndContainsNullableColumns(
                                foreignKey.DisplayName(),
                                index.GetDatabaseName(),
                                nullablePrincipalProperties.Select(tuple => tuple.column.DisplayName()).ToList()
                                .Aggregate((a, b) => a + "," + b)));

                        nullablePrincipalProperties
                        .ToList()
                        .ForEach(tuple => tuple.property.IsNullable = false);
                    }

                    principalKey = principalEntityType.AddKey(principalProperties);
                }
                else
                {
                    var principalColumns = foreignKey.PrincipalColumns.Select(c => c.Name).ToList();

                    _reporter.WriteWarning(
                        DesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound(
                            foreignKey.DisplayName(),
                            string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, principalColumns),
                            principalEntityType.DisplayName()));

                    return(null);
                }
            }

            var newForeignKey = dependentEntityType.AddForeignKey(
                dependentProperties, principalKey, principalEntityType);

            var dependentKey     = dependentEntityType.FindKey(dependentProperties);
            var dependentIndexes = dependentEntityType.GetIndexes()
                                   .Where(i => i.Properties.SequenceEqual(dependentProperties));

            newForeignKey.IsUnique = dependentKey != null ||
                                     dependentIndexes.Any(i => i.IsUnique);

            if (!string.IsNullOrEmpty(foreignKey.Name) &&
                foreignKey.Name != newForeignKey.GetDefaultName())
            {
                newForeignKey.SetConstraintName(foreignKey.Name);
            }

            AssignOnDeleteAction(foreignKey, newForeignKey);

            newForeignKey.AddAnnotations(foreignKey.GetAnnotations());

            return(newForeignKey);
        }
 public static DatabaseColumn GetPrincipalColumn(this DatabaseForeignKey fk)
 {
     return(fk.PrincipalColumns.Single());
 }
 protected virtual bool AcceptForeignKey(DatabaseForeignKey foreignKey) => true;
Exemple #30
0
        private void GetForeignKeys()
        {
            var command = _connection.CreateCommand();

            command.CommandText =
                "SHOW " +
                "    ForeignKeys " +
                "ORDER BY " +
                "    ToTable, " +
                "    ConstraintId, " +
                "    Ordinal";

            using (var reader = command.ExecuteReader())
            {
                var lastFkName                = string.Empty;
                var lastFkSchemaName          = string.Empty;
                var lastFkTableName           = string.Empty;
                DatabaseForeignKey foreignKey = null;
                while (reader.Read())
                {
                    var schemaName               = "Jet";
                    var tableName                = reader.GetValueOrDefault <string>("FromTable");
                    var constraintName           = reader.GetValueOrDefault <string>("ConstraintId");
                    var principalTableSchemaName = "Jet";
                    var principalTableName       = reader.GetValueOrDefault <string>("ToTable");
                    var fromColumnName           = reader.GetValueOrDefault <string>("FromColumn");
                    var toColumnName             = reader.GetValueOrDefault <string>("ToColumn");
                    var updateAction             = reader.GetValueOrDefault <string>("UpdateRule");
                    var deleteAction             = reader.GetValueOrDefault <string>("DeleteRule");
                    var ordinal = reader.GetValueOrDefault <int>("Ordinal");

                    Logger.ForeignKeyColumnFound(
                        DisplayName(schemaName, tableName), constraintName, DisplayName(principalTableSchemaName, principalTableName),
                        fromColumnName, toColumnName, updateAction, deleteAction, ordinal);

                    if (foreignKey == null ||
                        lastFkSchemaName != schemaName ||
                        lastFkTableName != tableName ||
                        lastFkName != constraintName)
                    {
                        lastFkName       = constraintName;
                        lastFkSchemaName = schemaName;
                        lastFkTableName  = tableName;

                        if (!_tables.TryGetValue(SchemaQualifiedKey(tableName, schemaName), out var table))
                        {
                            Logger.ForeignKeyTableMissingWarning(constraintName, DisplayName(schemaName, tableName));
                            continue;
                        }

                        DatabaseTable principalTable = null;
                        if (!string.IsNullOrEmpty(principalTableSchemaName) &&
                            !string.IsNullOrEmpty(principalTableName))
                        {
                            _tables.TryGetValue(SchemaQualifiedKey(principalTableName, principalTableSchemaName), out principalTable);
                        }

                        if (principalTable == null)
                        {
                            Logger.ForeignKeyReferencesMissingPrincipalTableWarning(
                                constraintName, DisplayName(schemaName, tableName), DisplayName(principalTableSchemaName, principalTableName));
                        }

                        foreignKey = new DatabaseForeignKey
                        {
                            Name           = constraintName,
                            Table          = table,
                            PrincipalTable = principalTable,
                            OnDelete       = ConvertToReferentialAction(deleteAction)
                        };

                        table.ForeignKeys.Add(foreignKey);
                    }

                    if (_tableColumns.TryGetValue(
                            ColumnKey(foreignKey.Table, fromColumnName), out var fromColumn))
                    {
                        foreignKey.Columns.Add(fromColumn);
                    }

                    if (foreignKey.PrincipalTable != null)
                    {
                        if (_tableColumns.TryGetValue(
                                ColumnKey(foreignKey.PrincipalTable, toColumnName), out var toColumn))
                        {
                            foreignKey.PrincipalColumns.Add(toColumn);
                        }
                    }
                }
            }
        }