EF5 Code First-Cambiar Un Tipo De Columna Con Migraciones


Soy nuevo en el Código EF5 Primero y estoy retocando con una prueba de concepto antes de embarcarme en un proyecto en el trabajo.

Inicialmente he creado un modelo que parecía algo como

public class Person {
  public int Id { get; set; }
  public string FirstName { get; set;}
  public string Surname {get;set;}
  public string Location {get;set;}
}

Y he añadido algunos registros utilizando una pequeña aplicación MVC me pegué en la parte superior.

Ahora quiero cambiar la columna Ubicación a una enumeración, algo así como:

public class Person {
  public int Id { get; set; }
  public string FirstName { get; set;}
  public string Surname {get;set;}
  public Locations Location {get;set;}
}

public enum Locations {
  London = 1,
  Edinburgh = 2,
  Cardiff = 3
}

Cuando agrego la nueva migración obtengo:

AlterColumn("dbo.People", "Location", c => c.Int(nullable: false));

Pero cuando corro update-database obtengo un error

Conversion failed when converting the nvarchar value 'London' to data type int.

¿Hay alguna forma en la migración de truncar la tabla antes de que ejecute la instrucción alter?

Sé que puedo abrir la base de datos y hacerlo manualmente, pero ¿hay una manera más inteligente?

Author: Nick, 2013-02-12

3 answers

La forma más inteligente es probablemente no alterar los tipos. Si necesitas hacer esto, te sugiero que hagas los siguientes pasos:

  1. Agregue una nueva columna con su nuevo tipo
  2. Use Sql() para hacerse cargo de los datos de la columna original utilizando una instrucción update
  3. Eliminar la columna anterior
  4. Cambiar el nombre de la nueva columna

Todo esto se puede hacer en la misma migración, se creará el script SQL correcto. Puede omitir el paso 2, si desea que sus datos sean descartadas. Si si desea tomar el control, agregue la instrucción apropiada (también puede contener una instrucción switch).

Desafortunadamente, las migraciones de Código Primero no proporcionan formas más fáciles de lograr esto.

Aquí está el código de ejemplo:

AddColumn("dbo.People", "LocationTmp", c => c.Int(nullable: false));
Sql(@"
    UPDATE dbp.People
    SET LocationTmp =
        CASE Location
            WHEN 'London' THEN 1
            WHEN 'Edinburgh' THEN 2
            WHEN 'Cardiff' THEN 3
            ELSE 0
        END
    ");
DropColumn("dbo.People", "Location");
RenameColumn("dbo.People", "LocationTmp", "Location");
 49
Author: JustAnotherUserYouMayKnow,
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-12-20 15:14:56

Basado en la respuesta de @JustAnotherUserYouMayKnow, pero más fácil.

Intente primero ejecutar Sql() comando y luego AlterColumn():

Sql(@"
    UPDATE dbo.People
    SET Location =
        CASE Location
            WHEN 'London' THEN 1
            WHEN 'Edinburgh' THEN 2
            WHEN 'Cardiff' THEN 3
            ELSE 0
        END
    ");
AlterColumn("dbo.People", "Location", c => c.Int(nullable: false));
 15
Author: Seven,
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-01-03 22:16:13

Sé que esto no se aplica directamente a la pregunta, pero podría ser útil para alguien. En mi problema, accidentalmente hice un campo de año un datetime y estaba tratando de averiguar cómo eliminar todos los datos y luego cambiar el tipo de datos a un int.

Al hacer una migración de complementos, EF quería simplemente actualizar la columna. Tuve que borrar lo que querían hacer y añadir mi propio código. Básicamente dejé caer la columna y agregué una nueva columna. Esto es lo que funcionó para mí.

protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "TestingPeriodYear",
            table: "ControlActivityIssue");

        migrationBuilder.AddColumn<int>(
            name: "TestingPeriodYear",
            table: "ControlActivityIssue",
            nullable: true);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "TestingPeriodYear",
            table: "ControlActivityIssue");

        migrationBuilder.AddColumn<DateTime>(
            name: "TestingPeriodYear",
            table: "ControlActivityIssue",
            nullable: true);
    }
 0
Author: Ben,
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-09-17 17:24:54