public void CallingForeignKeySetForeignKey()
        {
            var expressionMock = new Mock <CreateTableExpression>();
            var contextMock    = new Mock <IMigrationContext>();

            contextMock.SetupGet(x => x.Expressions).Returns(new List <IMigrationExpression>());
            var builder = new CreateTableExpressionBuilder(expressionMock.Object, contextMock.Object);

            builder.CurrentColumn = new ColumnDefinition();

            var fk = new ForeignKeyDefinition
            {
                Name               = "foreignKeyName",
                PrimaryTable       = "primaryTableName",
                PrimaryTableSchema = "primaryTableSchema",
                ForeignTable       = builder.Expression.TableName,
                ForeignTableSchema = builder.Expression.SchemaName
            };

            builder.ForeignKey(fk.Name, fk.PrimaryTableSchema, fk.PrimaryTable, "primaryColumnName");
            Assert.IsTrue(builder.CurrentColumn.IsForeignKey);
            Assert.AreEqual(builder.CurrentColumn.ForeignKey.Name, fk.Name);
            Assert.AreEqual(builder.CurrentColumn.ForeignKey.PrimaryTable, fk.PrimaryTable);
            Assert.AreEqual(builder.CurrentColumn.ForeignKey.PrimaryTableSchema, fk.PrimaryTableSchema);
            Assert.AreEqual(builder.CurrentColumn.ForeignKey.ForeignTable, fk.ForeignTable);
            Assert.AreEqual(builder.CurrentColumn.ForeignKey.ForeignTableSchema, fk.ForeignTableSchema);
        }
Example #2
0
        public override IMigrationExpression Reverse()
        {
            // there are 2 types of delete FK statements
            //  1) Delete.ForeignKey("FK_Name").OnTable("Table")
            //  2) Delete.ForeignKey()
            //      .FromTable("Table1").ForeignColumn("Id")
            //      .ToTable("Table2").PrimaryColumn("Id");

            // there isn't a way to autoreverse the type 1
            //  but we can turn the type 2 into Create.ForeignKey().FromTable() ...

            // only type 1 has the specific FK Name so if it's there then we can't auto-reverse
            if (!String.IsNullOrEmpty(ForeignKey.Name))
            {
                return(base.Reverse());
            }

            var reverseForeignKey = new ForeignKeyDefinition
            {
                Name = ForeignKey.Name,
                ForeignTableSchema = ForeignKey.PrimaryTableSchema,
                ForeignTable       = ForeignKey.PrimaryTable,
                PrimaryTableSchema = ForeignKey.ForeignTableSchema,
                PrimaryTable       = ForeignKey.ForeignTable,
                ForeignColumns     = new List <string>(ForeignKey.PrimaryColumns),
                PrimaryColumns     = new List <string>(ForeignKey.ForeignColumns),
                OnDelete           = ForeignKey.OnDelete,
                OnUpdate           = ForeignKey.OnUpdate
            };

            return(new CreateForeignKeyExpression {
                ForeignKey = reverseForeignKey
            });
        }
        /// <inheritdoc />
        public override IMigrationExpression Reverse()
        {
            // there are 2 types of delete FK statements
            //  1) Delete.ForeignKey("FK_Name").OnTable("Table")
            //  2) Delete.ForeignKey()
            //      .FromTable("Table1").ForeignColumn("Id")
            //      .ToTable("Table2").PrimaryColumn("Id");

            // there isn't a way to autoreverse the type 1
            //  but we can turn the type 2 into Create.ForeignKey().FromTable() ...

            // only type 2 has foreign column(s) and primary column(s)
            if (!ForeignKey.HasForeignAndPrimaryColumnsDefined())
            {
                return(base.Reverse());
            }
            var reverseForeignKey = new ForeignKeyDefinition {
                Name = ForeignKey.Name,
                ForeignTableSchema = ForeignKey.PrimaryTableSchema,
                ForeignTable       = ForeignKey.PrimaryTable,
                PrimaryTableSchema = ForeignKey.ForeignTableSchema,
                PrimaryTable       = ForeignKey.ForeignTable,
                ForeignColumns     = new List <string>(ForeignKey.PrimaryColumns),
                PrimaryColumns     = new List <string>(ForeignKey.ForeignColumns),
                OnDelete           = ForeignKey.OnDelete,
                OnUpdate           = ForeignKey.OnUpdate
            };

            return(new CreateForeignKeyExpression {
                ForeignKey = reverseForeignKey
            });
        }
    public static TableDefinition GetTableDefinition(Type modelType, ISqlSyntaxProvider sqlSyntax)
    {
        // Looks for NPoco's TableNameAtribute for the name of the table
        // If no attribute is set we use the name of the Type as the default convention
        TableNameAttribute?tableNameAttribute = modelType.FirstAttribute <TableNameAttribute>();
        var tableName = tableNameAttribute == null ? modelType.Name : tableNameAttribute.Value;

        var tableDefinition = new TableDefinition {
            Name = tableName
        };
        var objProperties = modelType.GetProperties().ToList();

        foreach (PropertyInfo propertyInfo in objProperties)
        {
            // If current property has an IgnoreAttribute then skip it
            IgnoreAttribute?ignoreAttribute = propertyInfo.FirstAttribute <IgnoreAttribute>();
            if (ignoreAttribute != null)
            {
                continue;
            }

            // If current property has a ResultColumnAttribute then skip it
            ResultColumnAttribute?resultColumnAttribute = propertyInfo.FirstAttribute <ResultColumnAttribute>();
            if (resultColumnAttribute != null)
            {
                continue;
            }

            // Looks for ColumnAttribute with the name of the column, which would exist with ExplicitColumns
            // Otherwise use the name of the property itself as the default convention
            ColumnAttribute? columnAttribute  = propertyInfo.FirstAttribute <ColumnAttribute>();
            var              columnName       = columnAttribute != null ? columnAttribute.Name : propertyInfo.Name;
            ColumnDefinition columnDefinition =
                GetColumnDefinition(modelType, propertyInfo, columnName, tableName, sqlSyntax);
            tableDefinition.Columns.Add(columnDefinition);

            // Creates a foreignkey definition and adds it to the collection on the table definition
            IEnumerable <ForeignKeyAttribute>?foreignKeyAttributes =
                propertyInfo.MultipleAttribute <ForeignKeyAttribute>();
            if (foreignKeyAttributes != null)
            {
                foreach (ForeignKeyAttribute foreignKeyAttribute in foreignKeyAttributes)
                {
                    ForeignKeyDefinition foreignKeyDefinition = GetForeignKeyDefinition(modelType, propertyInfo, foreignKeyAttribute, columnName, tableName);
                    tableDefinition.ForeignKeys.Add(foreignKeyDefinition);
                }
            }

            // Creates an index definition and adds it to the collection on the table definition
            IndexAttribute?indexAttribute = propertyInfo.FirstAttribute <IndexAttribute>();
            if (indexAttribute != null)
            {
                IndexDefinition indexDefinition =
                    GetIndexDefinition(modelType, propertyInfo, indexAttribute, columnName, tableName);
                tableDefinition.Indexes.Add(indexDefinition);
            }
        }

        return(tableDefinition);
    }
        public static ForeignKeyDefinition GetForeignKeyDefinition(Type modelType, PropertyInfo propertyInfo,
                                                                   ForeignKeyAttribute attribute, string columnName, string tableName)
        {
            var referencedTable      = attribute.Type.FirstAttribute <TableNameAttribute>();
            var referencedPrimaryKey = attribute.Type.FirstAttribute <PrimaryKeyAttribute>();

            string referencedColumn = string.IsNullOrEmpty(attribute.Column)
                                          ? referencedPrimaryKey.Value
                                          : attribute.Column;

            string foreignKeyName = string.IsNullOrEmpty(attribute.Name)
                                        ? string.Format("FK_{0}_{1}_{2}", tableName, referencedTable.Value, referencedColumn)
                                        : attribute.Name;

            var definition = new ForeignKeyDefinition
            {
                Name         = foreignKeyName,
                ForeignTable = tableName,
                PrimaryTable = referencedTable.Value
            };

            definition.ForeignColumns.Add(columnName);
            definition.PrimaryColumns.Add(referencedColumn);

            return(definition);
        }
        private static CreateForeignKeyExpression GetCreateForeignKeyExpression(Table table, ForeignKey fk)
        {
            if (fk.ReferencedTable == null)
            {
                return(null);
            }

            var foreignKeyDefinition = new ForeignKeyDefinition()
            {
                Name = fk.Name,
                PrimaryTableSchema = fk.ReferencedTable.Schema,
                PrimaryTable       = fk.ReferencedTable.Name,
                ForeignTableSchema = table.Schema,
                ForeignTable       = table.Name,
                ForeignColumns     = fk.Columns.Select(c => c.Name).ToList(),
                PrimaryColumns     = fk.ReferencedColumns.Count > 0 ? fk.ReferencedColumns.Select(c => c.Name).ToList() : fk.ReferencedTable.PrimaryKey.ColumnIterator.Select(c => c.Name).ToList(),
                OnDelete           = fk.CascadeDeleteEnabled ? Rule.Cascade : Rule.None,
                OnUpdate           = Rule.None
            };

            return(new CreateForeignKeyExpression
            {
                ForeignKey = foreignKeyDefinition
            });
        }
Example #7
0
        /// <inheritdoc />
        public virtual string FormatForeignKey(ForeignKeyDefinition foreignKey,
                                               Func <ForeignKeyDefinition, string> fkNameGeneration)
        {
            if (foreignKey.PrimaryColumns.Count != foreignKey.ForeignColumns.Count)
            {
                throw new ArgumentException("Number of primary columns and secondary columns must be equal");
            }
            var constraintName = string.IsNullOrEmpty(foreignKey.Name)
                ? fkNameGeneration(foreignKey)
                : foreignKey.Name;
            var primaryColumns = new List <string>();
            var foreignColumns = new List <string>();

            foreach (var column in foreignKey.PrimaryColumns)
            {
                primaryColumns.Add(Quoter.QuoteColumnName(column));
            }
            foreach (var column in foreignKey.ForeignColumns)
            {
                foreignColumns.Add(Quoter.QuoteColumnName(column));
            }
            var constraintClause = string.IsNullOrEmpty(constraintName)
                ? string.Empty
                : $"CONSTRAINT {Quoter.QuoteConstraintName(constraintName)} ";

            return(string.Format(
                       ForeignKeyConstraint,
                       constraintClause,
                       string.Join(", ", foreignColumns.ToArray()),
                       Quoter.QuoteTableName(foreignKey.PrimaryTable, foreignKey.PrimaryTableSchema),
                       string.Join(", ", primaryColumns.ToArray()),
                       FormatCascade("DELETE", foreignKey.OnDelete),
                       FormatCascade("UPDATE", foreignKey.OnUpdate)
                       ));
        }
Example #8
0
 public static void ToLower(this ForeignKeyDefinition definition)
 {
     definition.Name           = definition.Name.ToLower();
     definition.ForeignTable   = definition.ForeignTable.ToLower();
     definition.PrimaryTable   = definition.PrimaryTable.ToLower();
     definition.ForeignColumns = definition.ForeignColumns.ToLower();
     definition.PrimaryColumns = definition.PrimaryColumns.ToLower();
 }
 public void Truncate(ForeignKeyDefinition foreignKey)
 {
     foreignKey.Name           = _packKeyNames ? Pack(foreignKey.Name) : Truncate(foreignKey.Name);
     foreignKey.PrimaryTable   = Truncate(foreignKey.PrimaryTable);
     foreignKey.PrimaryColumns = TruncateNames(foreignKey.PrimaryColumns);
     foreignKey.ForeignTable   = Truncate(foreignKey.ForeignTable);
     foreignKey.ForeignColumns = TruncateNames(foreignKey.ForeignColumns);
 }
        public void ErrorIsNotReturnedWhenPrimaryTableNameIsDifferentThanForeignTableName()
        {
            var column = new ForeignKeyDefinition {
                PrimaryTable = "Bacon", ForeignTable = "NotBacon"
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldNotContain(ErrorMessages.ForeignKeyCannotBeSelfReferential);
        }
        /// <summary>
        /// Gets the default name of a foreign key
        /// </summary>
        /// <param name="foreignKey">The foreign key definition</param>
        /// <returns>Name of a foreign key</returns>
        private string GetForeignKeyName(ForeignKeyDefinition foreignKey)
        {
            var foreignColumns = string.Join('_', foreignKey.ForeignColumns);
            var primaryColumns = string.Join('_', foreignKey.PrimaryColumns);

            var keyName = _dataProvider.CreateForeignKeyName(foreignKey.ForeignTable, foreignColumns, foreignKey.PrimaryTable, primaryColumns);

            return(keyName);
        }
Example #12
0
        public void ErrorIsReturnedWhenPrimaryTableNameIsNull()
        {
            var column = new ForeignKeyDefinition {
                PrimaryTable = null
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldContain(ErrorMessages.PrimaryTableNameCannotBeNullOrEmpty);
        }
Example #13
0
        public void ErrorIsReturnedWhenForeignTableNameIsEmptyString()
        {
            var column = new ForeignKeyDefinition {
                ForeignTable = string.Empty
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldContain(ErrorMessages.ForeignTableNameCannotBeNullOrEmpty);
        }
Example #14
0
        public void ErrorIsNotReturnedWhenNameIsNotNullOrEmptyString()
        {
            var column = new ForeignKeyDefinition {
                Name = "Bacon"
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldNotContain(ErrorMessages.ForeignKeyNameCannotBeNullOrEmpty);
        }
Example #15
0
        public void ErrorIsReturnedWhenPrimaryColumnsIsEmpty()
        {
            var column = new ForeignKeyDefinition {
                Name = "FkName", ForeignTable = "FkTable", PrimaryTable = "PkTable", PrimaryColumns = new string[0]
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldContain(ErrorMessages.ForeignKeyMustHaveOneOrMorePrimaryColumns);
        }
        public void ErrorIsReturnedWhenForeignColumnsIsEmpty()
        {
            var column = new ForeignKeyDefinition {
                ForeignColumns = new string[0]
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldContain(ErrorMessages.ForeignKeyMustHaveOneOrMoreForeignColumns);
        }
Example #17
0
        public void ErrorIsNotReturnedWhenPrimaryColumnsIsNotEmpty()
        {
            var column = new ForeignKeyDefinition {
                PrimaryColumns = new[] { "Bacon" }
            };
            var errors = ValidationHelper.CollectErrors(column);

            errors.ShouldNotContain(ErrorMessages.ForeignKeyMustHaveOneOrMorePrimaryColumns);
        }
Example #18
0
 public override string Format(ForeignKeyDefinition foreignKey)
 {
     return(string.Format(CreateForeignKeyConstraint,
                          GetQuotedTableName(foreignKey.ForeignTable),
                          GetQuotedColumnName(foreignKey.ForeignColumns.First()),
                          GetQuotedTableName(foreignKey.PrimaryTable),
                          GetQuotedColumnName(foreignKey.PrimaryColumns.First()),
                          FormatCascade("DELETE", foreignKey.OnDelete),
                          FormatCascade("UPDATE", foreignKey.OnUpdate)));
 }
        /// <inheritdoc />
        public override string FormatForeignKey(ForeignKeyDefinition foreignKey, Func <ForeignKeyDefinition, string> fkNameGeneration)
        {
            var fk2 = (ForeignKeyDefinition)foreignKey.Clone();

            // SQLite FK's must be within the same schema as the FK itself
            // so we'll remove the schema from the FK definition
            fk2.PrimaryTableSchema = string.Empty;

            return(base.FormatForeignKey(fk2, fkNameGeneration));
        }
Example #20
0
        public void GetForeignKeyNameReturnsValidForeignKeyNameForComplexForeignKey()
        {
            var foreignKey = new ForeignKeyDefinition
            {
                ForeignTable = "Users", ForeignColumns = new[] { "ColumnA", "ColumnB" },
                PrimaryTable = "Groups", PrimaryColumns = new[] { "ColumnC", "ColumnD" }
            };

            DefaultMigrationConventions.GetForeignKeyName(foreignKey).ShouldBe("FK_Users_ColumnA_ColumnB_Groups_ColumnC_ColumnD");
        }
Example #21
0
        public void GetForeignKeyNameReturnsValidForeignKeyNameForSimpleForeignKey()
        {
            var foreignKey = new ForeignKeyDefinition
            {
                ForeignTable = "Users", ForeignColumns = new[] { "GroupId" },
                PrimaryTable = "Groups", PrimaryColumns = new[] { "Id" }
            };

            DefaultMigrationConventions.GetForeignKeyName(foreignKey).ShouldBe("FK_Users_GroupId_Groups_Id");
        }
        public void WhenDefaultSchemaConventionIsAppliedAndSchemaIsSetThenSchemaShouldNotBeChanged()
        {
            var foreignKeyDefinition = new ForeignKeyDefinition {
                Name = "Test", ForeignTableSchema = "testschema", PrimaryTableSchema = "testschema"
            };

            foreignKeyDefinition.ApplyConventions(new MigrationConventions());

            Assert.That(foreignKeyDefinition.ForeignTableSchema, Is.EqualTo("testschema"));
            Assert.That(foreignKeyDefinition.PrimaryTableSchema, Is.EqualTo("testschema"));
        }
        public void WhenDefaultSchemaConventionIsAppliedAndSchemaIsNotSetThenSchemaShouldBeNull()
        {
            var foreignKeyDefinition = new ForeignKeyDefinition {
                Name = "Test"
            };

            foreignKeyDefinition.ApplyConventions(new MigrationConventions());

            Assert.That(foreignKeyDefinition.ForeignTableSchema, Is.Null);
            Assert.That(foreignKeyDefinition.PrimaryTableSchema, Is.Null);
        }
        private void LoadConstraints()
        {
            Constraints = ConstraintInfo.Read(Processor, TableMeta);
            foreach (ConstraintInfo constraint in Constraints)
            {
                List <string> columns = new List <string>();
                if (Indexes.Any(x => x.Name == constraint.IndexName))
                {
                    columns = Indexes.First(x => x.Name == constraint.IndexName).Columns;
                }

                foreach (ColumnDefinition column in Definition.Columns)
                {
                    if (columns.Contains(column.Name))
                    {
                        if (constraint.IsPrimaryKey)
                        {
                            column.IsPrimaryKey   = true;
                            column.PrimaryKeyName = constraint.Name;
                            RemoveIndex(constraint.Name);
                        }

                        if (constraint.IsNotNull)
                        {
                            column.IsNullable = false;
                        }

                        if (constraint.IsUnique)
                        {
                            column.IsUnique = true;
                        }
                    }
                }

                if (constraint.IsForeignKey)
                {
                    ForeignKeyDefinition fkDef = new ForeignKeyDefinition()
                    {
                        Name           = constraint.Name,
                        ForeignTable   = TableMeta.Name,
                        ForeignColumns = columns,
                        PrimaryTable   = constraint.ForeignIndex.TableName,
                        PrimaryColumns = constraint.ForeignIndex.Columns,
                        OnUpdate       = constraint.UpdateRule,
                        OnDelete       = constraint.DeleteRule
                    };

                    RemoveIndex(constraint.Name);

                    Definition.ForeignKeys.Add(fkDef);
                }
            }
        }
 private bool AreSameFk(ForeignKeyDefinition fromFk, ForeignKeyDefinition toFk)
 {
     return(fromFk.Name == toFk.Name &&
            fromFk.ForeignTableSchema == toFk.ForeignTableSchema &&
            fromFk.ForeignTable == toFk.ForeignTable &&
            fromFk.PrimaryTable == toFk.PrimaryTable &&
            fromFk.PrimaryTableSchema == toFk.PrimaryTableSchema &&
            fromFk.OnDelete == toFk.OnDelete &&
            fromFk.OnUpdate == toFk.OnUpdate &&
            MatchStrings(fromFk.ForeignColumns, toFk.ForeignColumns) &&
            MatchStrings(fromFk.PrimaryColumns, toFk.PrimaryColumns));
 }
Example #26
0
        public void Delete_Foreign_Key_Should_Throw_Exception_If_Table_Name_Is_Null()
        {
            // Setup empty FK
            var deleteFKExpression = new DeleteForeignKeyExpression();
            var fkDef = new ForeignKeyDefinition();

            deleteFKExpression.ForeignKey = fkDef;

            // Setup empty mock object
            var mockGenerator = new MockGenerator(null, null);

            Assert.Throws <ArgumentNullException>(() => mockGenerator.Generate(deleteFKExpression));
        }
        public void WhenDefaultSchemaConventionIsChangedAndSchemaIsNotSetThenSetSchema()
        {
            var foreignKeyDefinition = new ForeignKeyDefinition {
                Name = "Test"
            };
            var migrationConventions = new MigrationConventions {
                GetDefaultSchema = () => "testdefault"
            };

            foreignKeyDefinition.ApplyConventions(migrationConventions);

            Assert.That(foreignKeyDefinition.ForeignTableSchema, Is.EqualTo("testdefault"));
            Assert.That(foreignKeyDefinition.PrimaryTableSchema, Is.EqualTo("testdefault"));
        }
        public virtual string Format(ForeignKeyDefinition foreignKey)
        {
            var constraintName = string.IsNullOrEmpty(foreignKey.Name)
                ? $"FK_{foreignKey.ForeignTable}_{foreignKey.PrimaryTable}_{foreignKey.PrimaryColumns.First()}"
                : foreignKey.Name;

            return(string.Format(CreateForeignKeyConstraint,
                                 GetQuotedTableName(foreignKey.ForeignTable),
                                 GetQuotedName(constraintName),
                                 GetQuotedColumnName(foreignKey.ForeignColumns.First()),
                                 GetQuotedTableName(foreignKey.PrimaryTable),
                                 GetQuotedColumnName(foreignKey.PrimaryColumns.First()),
                                 FormatCascade("DELETE", foreignKey.OnDelete),
                                 FormatCascade("UPDATE", foreignKey.OnUpdate)));
        }
Example #29
0
    public virtual string Format(ForeignKeyDefinition foreignKey)
    {
        var constraintName = string.IsNullOrEmpty(foreignKey.Name)
            ? $"FK_{foreignKey.ForeignTable}_{foreignKey.PrimaryTable}_{foreignKey.PrimaryColumns.First()}"
            : foreignKey.Name;

        var localColumn = GetQuotedColumnName(foreignKey.ForeignColumns.First());
        var remoteColumn = GetQuotedColumnName(foreignKey.PrimaryColumns.First());
        var remoteTable = GetQuotedTableName(foreignKey.PrimaryTable);
        var onDelete = FormatCascade("DELETE", foreignKey.OnDelete);
        var onUpdate = FormatCascade("UPDATE", foreignKey.OnUpdate);

        return
            $"CONSTRAINT {constraintName} FOREIGN KEY ({localColumn}) REFERENCES {remoteTable} ({remoteColumn}) {onDelete} {onUpdate}";
    }
        public IAlterTableColumnOptionForeignKeyCascadeBuilder ReferencedBy(string?foreignKeyName, string?foreignTableSchema,
                                                                            string foreignTableName, string foreignColumnName)
        {
            var fk = new CreateForeignKeyExpression(_context, new ForeignKeyDefinition
            {
                Name               = foreignKeyName,
                PrimaryTable       = Expression.TableName,
                ForeignTable       = foreignTableName,
                ForeignTableSchema = foreignTableSchema
            });

            fk.ForeignKey.PrimaryColumns.Add(CurrentColumn.Name);
            fk.ForeignKey.ForeignColumns.Add(foreignColumnName);

            Expression.Expressions.Add(fk);
            CurrentForeignKey = fk.ForeignKey;
            return(this);
        }