Migración de HA para cambiar el tipo de datos de columnas


Tengo un Modelo en mi proyecto de la siguiente manera:

public class Model 
{
    public int Id { get; set; }
    public long FromNo { get; set; }
    public long ToNo { get; set; }
    public string Content { get; set; }
    public long TicketNo { get; set; }
}

La migración es la siguiente

public override void Down()
{
    AlterColumn("dbo.Received", "FromNo", c => c.Long(nullable: false));
    AlterColumn("dbo.Received", "ToNo", c => c.Long(nullable: false));
    AlterColumn("dbo.Received", "TicketNo", c => c.Long(nullable: false));
}
public override void Up()
{
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}

Cuando uso Update-Database se genera el siguiente error:

El objeto 'DF _ _ Receive _ _ FromN _ _ 25869641' depende de la columna "FromNo". ALTER TABLE ALTER COLUMN FromNo falló porque uno o más los objetos acceden a esta columna.

Estas tablas no tienen clave foránea o qué más, así que ¿cuál es el problema?

Author: Uwe Keim, 2013-07-27

6 answers

Tiene una restricción predeterminada en su columna. Primero debe eliminar la restricción y luego modificar su columna.

public override void Up()
{
    Sql("ALTER TABLE dbo.Received DROP CONSTRAINT DF_Receiv_FromN__25869641");
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}

Probablemente tendrá que eliminar las restricciones predeterminadas en sus otras columnas también.

Acabo de ver el comentario de Andrey (lo sé - muy tarde) y tiene razón. Así que un enfoque más robusto sería usar algo como:

 DECLARE @con nvarchar(128)
 SELECT @con = name
 FROM sys.default_constraints
 WHERE parent_object_id = object_id('dbo.Received')
 AND col_name(parent_object_id, parent_column_id) = 'FromNo';
 IF @con IS NOT NULL
     EXECUTE('ALTER TABLE [dbo].[Received] DROP CONSTRAINT ' + @con)

Sé que esto probablemente no ayuda a la OP, pero espero que ayude a cualquier otra persona que se encuentre con este problema.

 71
Author: James Hull,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-28 16:50:06
static internal class MigrationExtensions
{
    public static void DeleteDefaultContraint(this IDbMigration migration, string tableName, string colName, bool suppressTransaction = false)
    {
        var sql = new SqlOperation(String.Format(@"DECLARE @SQL varchar(1000)
        SET @SQL='ALTER TABLE {0} DROP CONSTRAINT ['+(SELECT name
        FROM sys.default_constraints
        WHERE parent_object_id = object_id('{0}')
        AND col_name(parent_object_id, parent_column_id) = '{1}')+']';
        PRINT @SQL;
        EXEC(@SQL);", tableName, colName)) { SuppressTransaction = suppressTransaction };
        migration.AddOperation(sql);
    }
}

public override void Up()
{
    this.DeleteDefaultContraint("dbo.Received", "FromNo");
    AlterColumn("dbo.Received", "FromNo", c => c.String());
    this.DeleteDefaultContraint("dbo.Received", "ToNo");
    AlterColumn("dbo.Received", "ToNo", c => c.String());
    this.DeleteDefaultContraint("dbo.Received", "TicketNo");
    AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
 39
Author: DTTerastar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-08 20:39:14

Este es un ejemplo para cambiar una columna existente a 'not null' que ya tiene una restricción de clave foránea. El nombre de la columna es " FKColumnName "en la tabla" SubTable "y hace referencia a la columna" Id "en la tabla"MainTable".

Up script:

Después de que la columna se hace 'not nullable', el índice y la clave foránea primero se sueltan y luego se vuelven a crear.

Abajo de la secuencia de comandos:

Aquí los pasos son idénticos excepto que la columna está hecha anulable de nuevo.

public partial class NameOfMigration : DbMigration
{
    public override void Up()
    {
        DropForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable");
        DropIndex("dbo.SubTable", new[] { "FKColumnName" });

        AlterColumn("dbo.SubTable", "FKColumnName", c => c.Int(nullable: false));

        CreateIndex("dbo.SubTable", "FKColumnName");
        AddForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable", "Id");
    }

    public override void Down()
    {
        DropForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable");
        DropIndex("dbo.SubTable", new[] { "FKColumnName" });

        AlterColumn("dbo.SubTable", "FKColumnName", c => c.Int(nullable: true));

        CreateIndex("dbo.SubTable", "FKColumnName");
        AddForeignKey("dbo.SubTable", "FKColumnName", "dbo.MainTable", "Id");
    }
}
 2
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-24 13:29:35

La mejor manera es resolver el problema para siempre.

Puede implementar una clase sql generator personalizada derivada de SqlServerMigrationSqlGenerator desde System.Datos.Entidad.Espacio de nombres SQLServer:

using System.Data.Entity.Migrations.Model;
using System.Data.Entity.SqlServer;

namespace System.Data.Entity.Migrations.Sql{
    internal class FixedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator {
        protected override void Generate(AlterColumnOperation alterColumnOperation){
            ColumnModel column = alterColumnOperation.Column;
            var sql = String.Format(@"DECLARE @ConstraintName varchar(1000);
            DECLARE @sql varchar(1000);
            SELECT @ConstraintName = name   FROM sys.default_constraints
                WHERE parent_object_id = object_id('{0}')
                AND col_name(parent_object_id, parent_column_id) = '{1}';
            IF(@ConstraintName is NOT Null)
                BEGIN
                set @sql='ALTER TABLE {0} DROP CONSTRAINT [' + @ConstraintName+ ']';
            exec(@sql);
            END", alterColumnOperation.Table, column.Name);
                this.Statement(sql);
            base.Generate(alterColumnOperation);
            return;
        }
        protected override void Generate(DropColumnOperation dropColumnOperation){
            var sql = String.Format(@"DECLARE @SQL varchar(1000)
                SET @SQL='ALTER TABLE {0} DROP CONSTRAINT [' + (SELECT name
                    FROM sys.default_constraints
                    WHERE parent_object_id = object_id('{0}')
                    AND col_name(parent_object_id, parent_column_id) = '{1}') + ']';
            PRINT @SQL;
                EXEC(@SQL); ", dropColumnOperation.Table, dropColumnOperation.Name);

                    this.Statement(sql);
            base.Generate(dropColumnOperation);
        }
    }
}

Y Establece esta configuración:

internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;

        SetSqlGenerator("System.Data.SqlClient", new FixedSqlServerMigrationSqlGenerator ());
    }
    ...
}
 2
Author: Elyas Dowlatabadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-18 13:21:12

Estaba teniendo este problema con un valor predeterminado de restricción cero en una columna entera.

En mi caso lo resolví cambiando de Entity Framework 6.1.x a EF 6.2.0.

Hay un error conocido en EF anterior a la 6.2 que significa que EF a veces no se ocupa de este tipo de restricciones automáticamente al alterar las columnas. Ese error se describe en el repositorio oficial de EF github aquí , Bricelam describe el problema como:

Al agregar columnas NO NULL, sintetizamos un valor predeterminado para cualquier filas existentes. Parece que nuestra lógica para eliminar las restricciones predeterminadas antes DE ALTER COLUMN no tiene esto en cuenta.

La confirmación de la corrección de ese problema se puede encontrar aquí.

 0
Author: tomRedox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 01:08:43

Si estás usando EF:

  • Eliminar la carpeta de migración y la base de datos
  • enable-migrations
  • add-migration initial
  • update-database

Aunque, esta solución eliminaría todos los elementos actuales de la base de datos. Si esta no es su intención, sugeriría una de las otras respuestas.

 -10
Author: Mostafa Basha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-30 21:17:55