Entity Framework: migración de Code First

Entity Framework 4.3 incluye una nueva función de migraciones de Code First que le permite evolucionar gradualmente el esquema de la base de datos a medida que su modelo cambia con el tiempo. Para la mayoría de los desarrolladores, esta es una gran mejora con respecto a las opciones de inicialización de la base de datos de las versiones 4.1 y 4.2 que requerían que actualizara manualmente la base de datos o la eliminara y recreara cuando tu modelo cambiara.

  • Antes de Entity Framework 4.3, si ya tiene datos (que no sean datos iniciales) o procedimientos almacenados, desencadenadores, etc., existentes en su base de datos, estas estrategias solían eliminar toda la base de datos y recrearla, por lo que perdería los datos y otras bases de datos. objetos.

  • Con la migración, actualizará automáticamente el esquema de la base de datos, cuando su modelo cambie sin perder ningún dato existente u otros objetos de la base de datos.

  • Utiliza un nuevo inicializador de base de datos llamado MigrateDatabaseToLatestVersion.

Hay dos tipos de migración:

  • Migración automatizada
  • Migración basada en código

Migración automatizada

La migración automatizada se introdujo por primera vez en Entity framework 4.3. En la migración automatizada, no es necesario procesar la migración de la base de datos manualmente en el archivo de código. Por ejemplo, para cada cambio, también deberá cambiar sus clases de dominio. Pero con la migración automatizada, solo tiene que ejecutar un comando en la Consola del Administrador de paquetes para hacer esto.

Echemos un vistazo al siguiente proceso paso a paso de migración automatizada.

Cuando usa el enfoque Code First, no tiene una base de datos para su aplicación.

En este ejemplo, comenzaremos con nuestras 3 clases básicas, como Estudiante, Curso e Inscripción, como se muestra en el siguiente código.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

A continuación se muestra la clase de contexto.

public class MyContext : DbContext {
   public MyContext() : base("MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Antes de ejecutar la aplicación, debe habilitar la migración automatizada.

Step 1 - Abra la consola del administrador de paquetes desde Herramientas → Administrador de paquetes NuGet → Consola del administrador de paquetes.

Step 2 - Para habilitar la migración automatizada, ejecute el siguiente comando en Package Manager Console.

PM> enable-migrations -EnableAutomaticMigrations:$true

Step 3 - Una vez que el comando se ejecuta correctamente, crea una clase de configuración sellada interna en la carpeta de migración de su proyecto como se muestra en el siguiente código.

namespace EFCodeFirstDemo.Migrations {

   using System;
   using System.Data.Entity;
   using System.Data.Entity.Migrations;
   using System.Linq;
	
   internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstDemo.MyContext> {

      public Configuration() {
         AutomaticMigrationsEnabled = true;
         ContextKey = "EFCodeFirstDemo.MyContext";
      }

      protected override void Seed(EFCodeFirstDemo.MyContext context) {

         //  This method will be called after migrating to the latest version.
         //  You can use the DbSet<T>.AddOrUpdate() helper extension method
         //  to avoid creating duplicate seed data. E.g.

         //  context.People.AddOrUpdate(
            //  p ⇒ p.FullName, 
            //  new Person { FullName = "Andrew Peters" }, 
            //  new Person { FullName = "Brice Lambson" }, 
            //  new Person { FullName = "Rowan Miller" }
         //  );
      }
   }
}

Step 4 - Configure el inicializador de la base de datos en la clase de contexto con la nueva estrategia de inicialización de la base de datos MigrateDatabaseToLatestVersion.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, 
         EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 5- Ha configurado la migración automatizada. Cuando ejecute su aplicación, automáticamente se encargará de la migración, cuando cambie el modelo.

Step 6- Como puede ver, una tabla del sistema __MigrationHistory también se crea en su base de datos con otras tablas. En __MigrationHistory, la migración automatizada mantiene el historial de cambios en la base de datos.

Step 7- Cuando agrega otra clase de entidad como su clase de dominio y ejecuta su aplicación, entonces creará la tabla en su base de datos. Agreguemos la siguiente clase StudentLogIn.

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Step 8 - No olvide agregar el DBSet para la clase mencionada anteriormente en su clase de contexto como se muestra en el siguiente código.

public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }

Step 9 - Ejecute su aplicación nuevamente y verá que la tabla StudentsLogIn se agrega a su base de datos.

Los pasos anteriores mencionados para las migraciones automatizadas solo funcionarán para su entidad. Por ejemplo, para agregar otra clase de entidad o eliminar la clase de entidad existente, se migrará correctamente. Pero si agrega o elimina cualquier propiedad a su clase de entidad, arrojará una excepción.

Step 10 - Para manejar la migración de propiedades, debe establecer AutomaticMigrationDataLossAllowed = true en el constructor de la clase de configuración.

public Configuration() {
   AutomaticMigrationsEnabled = true;
   AutomaticMigrationDataLossAllowed = true;
   ContextKey = "EFCodeFirstDemo.MyContext";
}

Migración basada en código

Cuando desarrolla una nueva aplicación, su modelo de datos cambia con frecuencia, y cada vez que cambia el modelo, se desincroniza con la base de datos. Ha configurado Entity Framework para eliminar y volver a crear automáticamente la base de datos cada vez que cambia el modelo de datos. La migración basada en código es útil cuando desea tener más control sobre la migración.

  • Cuando agrega, elimina o cambia clases de entidad o cambia su clase DbContext, la próxima vez que ejecute la aplicación, automáticamente eliminará su base de datos existente, creará una nueva que coincide con el modelo y la inicializará con datos de prueba.

  • La función Code First Migrations resuelve este problema al permitir que Code First actualice el esquema de la base de datos en lugar de eliminar y volver a crear la base de datos. Para implementar la aplicación, deberá habilitar Migraciones.

Aquí está la regla básica para migrar cambios en la base de datos:

  • Habilitar migraciones
  • Agregar migración
  • Actualizar base de datos

Echemos un vistazo al siguiente proceso paso a paso de migración de código base.

Cuando utiliza el primer enfoque de código, no tiene una base de datos para su aplicación.

En este ejemplo, comenzaremos nuevamente con nuestras 3 clases básicas como Estudiante, Curso e Inscripción, como se muestra en el siguiente código.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

A continuación se muestra la clase de contexto.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<
         MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 1 - Antes de ejecutar la aplicación, debe habilitar la migración.

Step 2 - Abra la consola del Administrador de paquetes desde Herramientas → Administrador de paquetes NuGet → Consola del administrador de paquetes.

Step 3 - La migración ya está habilitada, ahora agregue la migración en su aplicación ejecutando el siguiente comando.

PM> add-migration "UniDB Schema"

Step 4 - Cuando el comando se ejecuta con éxito, verá que se ha creado un nuevo archivo en la carpeta Migración con el nombre del parámetro que pasó al comando con un prefijo de marca de tiempo como se muestra en la siguiente imagen.

Step 5 - Puede crear o actualizar la base de datos usando el comando "update-database".

PM> Update-Database -Verbose

El indicador "-Verbose" especifica mostrar las sentencias SQL que se aplican a la base de datos de destino en la consola.

Step 6 - Agreguemos una propiedad más 'Edad' en la clase del estudiante y luego ejecutemos la declaración de actualización.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public int Age { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

Cuando ejecute PM → Update-Database –Verbose, cuando el comando se ejecute correctamente, verá que la nueva columna Edad se agrega a su base de datos.

Le recomendamos que ejecute el ejemplo anterior paso a paso para una mejor comprensión.