Administración de migraciones

A medida que cambia el modelo, las migraciones se agregan y quitan como parte del desarrollo normal y los archivos de migración se revisan en el control de código fuente del proyecto. Para administrar las migraciones, primero debe instalar las herramientas de línea de comandos de EF Core.

Sugerencia

Si DbContext está en un ensamblado diferente al del proyecto de inicio, puede especificar de manera explícita los proyectos de destino e inicio tanto en las herramientas de la Consola del Administrador de paquetes como en las herramientas de la CLI de .NET Core.

Agregar una migración

Después de cambiar el modelo, puede agregar una migración para ese cambio:

dotnet ef migrations add AddBlogCreatedTimestamp

El nombre de la migración se puede usar como mensaje de confirmación en un sistema de control de versiones. Por ejemplo, puede elegir un nombre como AddBlogCreatedTimestamp si el cambio es una nueva CreatedTimestamp propiedad en la entidad Blog.

Se agregan tres archivos al proyecto en el directorio Migraciones:

  • XXXXXXXXXXXXXX_AddCreatedTimestamp.cs: el archivo de migraciones principal. Contiene las operaciones necesarias para aplicar la migración (en Up) y para revertirla (en Down).
  • XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs: el archivo de metadatos de las migraciones. Contiene información que usa EF.
  • MyContextModelSnapshot.cs: instantánea del modelo actual. Se usa para determinar qué ha cambiado al agregar la siguiente migración.

La marca de tiempo del nombre del archivo ayuda a mantenerlos ordenados cronológicamente para que se pueda ver la progresión de cambios.

Espacios de nombres

Puede mover los archivos de Migraciones y cambiar su espacio de nombres manualmente cuando quiera. Se crean nuevas migraciones como elementos del mismo nivel de la última migración. Como alternativa, puede especificar el directorio en tiempo de generación de la siguiente manera:

dotnet ef migrations add InitialCreate --output-dir Your/Directory

Nota:

También puede cambiar el espacio de nombres independientemente del directorio mediante --namespace.

Personalización del código de migración

Aunque EF Core generalmente crea migraciones precisas, siempre debe revisar el código y asegurarse de que corresponda al cambio deseado; en algunos casos, incluso es necesario hacerlo.

Cambio de nombre de columnas

Un ejemplo notable en el que se requiere la personalización de migraciones es cuando se cambia el nombre de una propiedad. Por ejemplo, si cambia el nombre de una propiedad de Name a FullName, EF Core generará la siguiente migración:

migrationBuilder.DropColumn(
    name: "Name",
    table: "Customers");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customers",
    nullable: true);

Por lo general, EF Core no puede saber cuándo la intención sea quitar una columna y crear una nueva (dos cambios diferentes) y cuándo sea cambiar el nombre de una columna. Si la migración anterior se aplica tal como está, se perderán todos los nombres de los clientes. Para cambiar el nombre de una columna, reemplace la migración generada anteriormente por lo siguiente:

migrationBuilder.RenameColumn(
    name: "Name",
    table: "Customers",
    newName: "FullName");

Sugerencia

El proceso de scaffolding de la migración advierte si una operación puede ocasionar una pérdida de datos (como el borrado de una columna). Si aparece dicha advertencia, asegúrese especialmente de revisar el código de las migraciones para mayor precisión.

Agregar SQL sin formato

Aunque se puede cambiar el nombre de una columna a través de una API integrada, en muchos casos no es posible. Por ejemplo, es posible que deseemos reemplazar las propiedades FirstName y LastName existentes por una sola propiedad FullName nueva. La migración generada por EF Core será la siguiente:

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

Como antes, esto provocaría una pérdida de datos no deseada. Para transferir los datos de las columnas antiguas, reorganizamos las migraciones e introducimos una operación SQL sin procesar como se indica a continuación:

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

migrationBuilder.Sql(
@"
    UPDATE Customer
    SET FullName = FirstName + ' ' + LastName;
");

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

Cambios arbitrarios a través de SQL sin procesar

SQL sin procesar también se puede usar para administrar objetos de base de datos que EF Core no conoce. Para ello, agregue una migración sin realizar ningún cambio de modelo. Se generará una migración vacía que después puede rellenar con operaciones SQL sin procesar.

Por ejemplo, la migración siguiente crea un procedimiento almacenado de SQL Server:

migrationBuilder.Sql(
@"
    EXEC ('CREATE PROCEDURE getFullName
        @LastName nvarchar(50),
        @FirstName nvarchar(50)
    AS
        RETURN @LastName + @FirstName;')");

Sugerencia

EXEC se usa cuando una instrucción debe ser la primera o solo una en un lote de SQL. También se puede usar para solucionar errores del analizador en scripts de migración idempotentes que pueden producirse cuando las columnas a las que se hace referencia no existen actualmente en una tabla.

Esto se puede usar para administrar cualquier aspecto de la base de datos, entre los que se incluyen:

  • procedimientos almacenados
  • Búsqueda de texto completo
  • Functions
  • Desencadenadores
  • Vistas

En la mayoría de los casos, EF Core ajustará automáticamente cada migración en su propia transacción al aplicar las migraciones. Desafortunadamente, algunas operaciones de migración no se pueden realizar dentro de una transacción en algunas bases de datos; en estos casos, puede no participar en la transacción pasando suppressTransaction: true a migrationBuilder.Sql.

Quitar una migración

A veces uno agrega una migración y se da cuenta de que debe realizar cambios adicionales en el modelo de EF Core antes de aplicarla. Para quitar la última migración, use este comando.

dotnet ef migrations remove

Después de quitar la migración, puede realizar los cambios de modelo adicionales y volver a agregarla.

Advertencia

Evite quitar las migraciones que ya se hayan aplicado a las bases de datos de producción. Si lo hace, no podrá revertir esas migraciones de las bases de datos y podría interrumpir las suposiciones realizadas por las migraciones posteriores.

Enumeración de migraciones

Puede enumerar todas las migraciones existentes de la siguiente manera:

dotnet ef migrations list

Comprobando los cambios de modelo pendientes

Nota:

Esta característica se agregó en EF Core 8.0.

A veces, es posible que desee comprobar si se han realizado cambios en el modelo desde la última migración. Esto puede ayudarle a saber cuándo un compañero de equipo olvidó agregar una migración. Una manera de hacerlo es usar este comando.

dotnet ef migrations has-pending-model-changes

También puede realizar esta comprobación mediante programación usando context.Database.HasPendingModelChanges(). Esto se puede usar para escribir una prueba unitaria que produce un error cuando se olvida de agregar una migración.

Restablecer todas las migraciones

En algunos casos extremos, podría ser necesario quitar todas las migraciones y empezar de nuevo. Esto se puede hacer fácilmente mediante la eliminación de la carpeta Migraciones y la anulación de la base de datos; en ese momento puede crear una nueva migración inicial que contendrá todo el esquema actual.

También es posible restablecer todas las migraciones y crear una sola sin perder los datos. Esto a veces se denomina "squashing" e implica algo de trabajo manual:

  1. Haga una copia de seguridad de la base de datos, en caso de que algo salga mal.
  2. En la base de datos, elimine todas las filas de la tabla del historial de migraciones (por ejemplo, DELETE FROM [__EFMigrationsHistory] en SQL Server).
  3. Elimine la carpeta Migraciones.
  4. Cree una nueva migración y genere un script de SQL para ella (dotnet ef migrations script).
  5. Inserte una sola fila en el historial de migraciones para registrar que ya se ha aplicado la primera migración, en vista de que las tablas ya están allí. La inserción de SQL es la última operación del script de SQL generado anteriormente y es similar a la siguiente (no olvide actualizar los valores):
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');

Advertencia

Cualquier código de migración personalizado se perderá cuando se elimine la carpeta Migraciones. Las personalizaciones deben aplicarse manualmente a la nueva migración inicial para conservarse.

Recursos adicionales