Compartir a través de


Migraciones de Code First con una base de datos que ya existe

Nota:

Solo EF 4.3 y versiones posteriores: las características, API, etc. que se tratan en esta página se introdujeron en Entity Framework 4.1. Si usa una versión anterior, no se aplica parte o la totalidad de la información.

En este artículo se describe el uso de Migraciones de Code First con una base de datos que ya existe y que no creó Entity Framework.

Nota:

En este artículo se da por supuesto que sabe cómo usar Migraciones de Code First en escenarios básicos. Si no es así, debe leer Migraciones de Code First antes de continuar.

Paso 1: Crear un modelo

El primer paso es crear un modelo de Code First destinado a la base de datos que ya existe. El tema Code First para una base de datos existente proporciona instrucciones detalladas sobre cómo hacerlo.

Nota:

Es importante seguir el resto de los pasos descritos en este tema antes de realizar cambios en el modelo que requerirían cambios en el esquema de la base de datos. Los siguientes pasos requieren que el modelo esté sincronizado con el esquema de la base de datos.

Paso 2: Habilitar las migraciones

El siguiente paso es habilitar las migraciones. Para ello, ejecute el comando Enable-Migrations en la consola del administrador de paquetes.

Este comando crea una carpeta en la solución denominada Migrations y pone una sola clase en ella denominada Configuration. La clase Configuration es donde se configuran las migraciones para la aplicación. Puede consultar más información sobre ella en el tema Migraciones de Code First.

Paso 3: Agregar una migración inicial

Una vez creadas y aplicadas las migraciones a la base de datos local, también puede aplicar estos cambios a otras bases de datos si lo desea. Por ejemplo, la base de datos local puede ser una base de datos de prueba y, finalmente, quizá desea aplicar también los cambios a una base de datos de producción o a bases de datos de prueba de otros desarrolladores. Hay dos opciones para este paso y la que debe elegir depende de si el esquema de cualquier otra base de datos está vacío o coincide actualmente con el esquema de la base de datos local.

  • Primera opción: Usar el esquema actual como punto de partida. Debe usar este enfoque cuando otras bases de datos a las que se aplicarán las migraciones en el futuro tendrán el mismo esquema que tiene actualmente la base de datos local. Por ejemplo, puede usar esta opción si la base de datos de prueba local coincide actualmente con la versión 1 de la base de datos de producción y, más adelante, aplicará estas migraciones para actualizar la base de datos de producción a la versión 2.
  • Segunda opción: Usar una base de datos vacía como punto de partida. Debe usar este enfoque cuando otras bases de datos a las que se aplicarán las migraciones en el futuro están vacías (o no existen aún). Por ejemplo, puede usar esto si ha empezado a desarrollar una aplicación usando una base de datos de prueba, pero sin usar migraciones y, más adelante, su intención es crear una base de datos de producción desde cero.

Primera opción: Usar el esquema actual como punto de partida

Migraciones de Code First usa una instantánea del modelo almacenado en la migración más reciente para detectar cambios en el modelo (puede consultar información detallada sobre esto en Migraciones de Code First en entornos de equipo). Dado que vamos a suponer que las bases de datos ya tienen el esquema del modelo actual, vamos a generar una migración vacía (sin operación) que tenga el modelo actual como instantánea.

  1. Ejecute el comando Add-Migration InitialCreate –IgnoreChanges en la consola del administrador de paquetes. Esto crea una migración vacía con el modelo actual como instantánea.
  2. Ejecute el comando Update-Database en la consola del administrador de paquetes. Esto aplica la migración InitialCreate a la base de datos. Dado que la migración real no contiene ningún cambio, simplemente agrega una fila a la tabla __MigrationsHistory para indicar que esta migración ya se ha aplicado.

Segunda opción: Usar una base de datos vacía como punto de partida

En este escenario, es necesario que Migraciones pueda crear toda la base de datos desde cero, incluidas las tablas que ya existen en la base de datos local. Vamos a generar una migración InitialCreate que incluya lógica para crear el esquema actual. A continuación, vamos a hacer que parezca que ya se ha aplicado esta migración a la base de datos actual.

  1. Ejecute el comando Add-Migration InitialCreate en la consola del administrador de paquetes. Esto crea una migración para crear el esquema actual.
  2. Convierta en comentario todo el código del método Up de la migración recién creada. Esto nos permitirá "aplicar" la migración a la base de datos local sin intentar volver a crear todas las tablas, etc. que ya existen.
  3. Ejecute el comando Update-Database en la consola del administrador de paquetes. Esto aplica la migración InitialCreate a la base de datos. Dado que la migración real no contiene ningún cambio (porque los hemos convertido en comentarios temporalmente), simplemente agrega una fila a la tabla __MigrationsHistory para indicar que esta migración ya se ha aplicado.
  4. Quite las marcas de comentario del código en el método Up. Esto significa que, cuando esta migración se aplique a bases de datos futuras, se creará mediante migraciones el esquema que ya existía en la base de datos local.

Aspectos que debe tener en cuenta

Hay algunas cosas que debe tener en cuenta cuando use Migraciones con una base de datos que ya existe.

Es posible que los nombres predeterminados o calculados no coincidan con el esquema actual

Migraciones especifica nombres para las columnas y las tablas de manera explícita cuando aplica scaffolding a una migración. Sin embargo, hay otros objetos de base de datos para los que Migraciones calcula un nombre predeterminado cuando aplica las migraciones. Entre estos objetos se incluyen los índices y las restricciones de clave externa. Al dirigirse a un esquema que ya existe, es posible que estos nombres calculados no coincidan con lo que realmente existen en la base de datos.

Estos son algunos ejemplos de cuándo debe tener esto en cuenta:

Si usó la "Primera opción: Usar el esquema actual como punto de partida" del paso 3:

  • Si los cambios futuros en el modelo requieren cambiar o quitar uno de los objetos de base de datos que tiene un nombre diferente, deberá modificar la migración a la que se ha aplicado scaffolding para especificar el nombre correcto. Las API de Migraciones tienen un parámetro Name opcional que permite hacer esto. Por ejemplo, el esquema actual puede tener una tabla Post con una columna de clave externa BlogId que tiene un índice denominado IndexFk_BlogId. Sin embargo, de forma predeterminada, Migraciones espera que este índice se denomine IX_BlogId. Si realiza un cambio en el modelo que da lugar a la eliminación de este índice, debe modificar la llamada a DropIndex con scaffolding para especificar el nombre de IndexFk_BlogId.

Si usó la "Segunda opción: Usar una base de datos vacía como punto de partida" del paso 3:

  • Si intenta ejecutar el método Down de la migración inicial (es decir, revertir a una base de datos vacía) respecto a la base de datos local, se puede producir un error, porque Migraciones intenta quitar los índices y las restricciones de clave externa que usan nombres incorrectos. Esto solo afecta a la base de datos local, ya que otras bases de datos se crean desde cero con el método Up de la migración inicial. Si desea degradar la base de datos local a un estado vacío, lo más fácil es hacerlo manualmente, ya sea quitando la base de datos o quitando todas las tablas. Después de esta degradación inicial, se vuelven a crear todos los objetos de la base de datos con los nombres predeterminados, de modo que no se presentará de nuevo este problema.
  • Si los cambios futuros en el modelo requieren cambiar o quitar uno de los objetos de base de datos que tienen un nombre diferente, esto no funcionará con la base de datos local que ya existe, porque los nombres no coincidirán con los valores predeterminados. Sin embargo, funcionará con las bases de datos que se crearon "desde cero", porque usarán los nombres predeterminados elegidos por Migraciones. Puede realizar estos cambios manualmente en la base de datos local o considerar la posibilidad de que Migraciones vuelva a crear la base de datos desde cero, como hará en otras máquinas.
  • Las bases de datos creadas con el método Up de la migración inicial pueden diferir ligeramente de la base de datos local, ya que se usarán los nombres predeterminados calculados para los índices y las restricciones de clave externa. También puede terminar con índices adicionales, ya que Migraciones crea índices en columnas de clave externa de forma predeterminada. Es posible que este no haya sido el caso en su base de datos local original.

No todos los objetos de base de datos se representan en el modelo

Migraciones no controla los objetos de base de datos que no forman parte del modelo. Puede tratarse de vistas, procedimientos almacenados, permisos, tablas que no forman parte del modelo, índices adicionales, etc.

Estos son algunos ejemplos de cuándo debe tener esto en cuenta:

  • Independientemente de la opción que elija en el "Paso 3", si los cambios futuros en el modelo requieren cambiar o quitar estos objetos adicionales, Migraciones no sabrá cómo hacer estos cambios. Por ejemplo, si quita una columna que tiene un índice adicional, Migraciones no sabrá cómo quitar el índice. Debe agregarlo manualmente a la migración a la que se ha aplicado scaffolding.
  • Si usa la "Segunda opción: Usar una base de datos vacía como punto de partida", estos objetos adicionales no se crean con el método Up de la migración inicial. Puede modificar los métodos Up y Down para controlar estos objetos adicionales si lo desea. En el caso de los objetos que no se admiten de forma nativa en la API Migraciones, como las vistas, puede usar el método Sql con el fin de ejecutar SQL puro para crearlos o quitarlos.