41

recientemente he cambiado de una aplicación desde el uso de los siguientes para dev:La confusión sobre EF Auto Migraciones y siembra - la siembra de cada programa se inicia

DropCreateDatabaseIfModelChanges<Context> 


Para usar:

public class MyDbMigrationsConfiguration: DbMigrationsConfiguration<GrsEntities> 
{ 
    public MyDbMigrationsConfiguration() 
    { 
     AutomaticMigrationsEnabled = true; 
     AutomaticMigrationDataLossAllowed = true; 
    } 
} 


En mi contexto db tengo:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // Tell Code First to ignore PluralizingTableName convention 
     // If you keep this convention then the generated tables will have pluralized names. 
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

     //set the initializer to migration 
     Database.SetInitializer(new MigrateDatabaseToLatestVersion<GrsEntities, MigrationConfig>()); 
    } 

He reemplazado a Seed (contexto) en DbMigrationsConfiguration usando la extensión AddOrUpdate donde estaba usando Agregar antes con siembra en el drop db (DropCreateDatabaseIfModelChanges).

Mi confusión es que la migración se ejecuta con cada inicio de la aplicación independientemente de que haya cambios en el DbContext. Cada vez que inicio la aplicación (la biblioteca se ejecuta a través de un servicio) el inicializador se ejecuta igual que la semilla. Mi comportamiento esperado es comprobar si una migración es necesaria (verificar entre bastidores para ver si el modelo coincide con la base de datos física) luego actualizar las tablas/columnas nuevas/eliminadas y solo ejecutar la semilla si algo ha cambiado.

En mi prueba, la semilla se ejecuta todo el tiempo, lo que es factible pero aparentemente ineficiente y no era lo que esperaba. Lamentablemente, la documentación de MSDN es bastante limitada.

¿Hago un uso incorrecto de MigrateDatabaseToLatestVersion? ¿Hay alguna manera de obtener el comportamiento que espero (es decir, solo semilla si hay un cambio de modelo) o debería simplemente cambiar mi método de inicialización para esperar que se ejecute cada lanzamiento de la aplicación?

Respuesta

58

El hecho de que el método Seed se ejecutó solo cuando la base de datos cambió fue bastante limitante para los inicializadores de base de datos que se enviaron en EF 4.1. Era limitante porque a veces era necesario actualizar los datos iniciales sin cambiar la base de datos, pero para que eso ocurriera, tenía que hacer que, artificialmente, pareciera que la base de datos había cambiado.

Con las migraciones, el uso de Seed se volvió un poco diferente porque ya no se podía suponer que la base de datos comenzaba vacía; ese es el punto de Migrations después de todo. Por lo tanto, un método de Seed en Migrations debe suponer que la base de datos existe y puede que ya tenga datos, pero es posible que sea necesario actualizar esos datos para tener en cuenta los cambios realizados en la base de datos para las Migraciones. De ahí el uso de AddOrUpdate.

Así que ahora tenemos una situación en la que la semilla debe ser escrito para tener en cuenta los datos existentes, lo que significa que en realidad no hay necesidad de perpetuar las limitaciones del método 4.1 Semilla EF tal que se tendría que hacer que parezca la base de datos había cambiado solo para poder ejecutar Seed. Por lo tanto, Seed ahora se ejecuta cada vez que el contexto se usa por primera vez en el dominio de la aplicación. Esto no debería cambiar la forma en que se incorpora Seed ya que necesita manejar el caso donde los datos ya están presentes de todos modos.

Si causa problemas de perfusión porque tiene una gran cantidad de datos de Semilla, entonces generalmente es muy fácil agregar comprobaciones en el método de Semilla que consulta la base de datos para determinar cuánto trabajo debe hacerse antes de hacerlo.

+0

Gracias Arthur. Eso fue claro, conciso y justo lo que estaba buscando. Terminé cambiando mi semilla para asumir que correría todas las veces, pero es bueno saber la historia detrás de ella (que no pude encontrar). – dubbreak

+9

El hecho de que el método de inicialización solo se ejecute cuando se realizó una migración y ahora el método de inicialización se ejecuta cada vez que se utiliza el contexto por primera vez es muy confuso. ¿Hay algún artículo de MSDN en alguna parte que detalle este cambio? –

2

Otra opción podría ser cargar una clase de inicializador db personalizada en tiempo de ejecución dentro del método de inicialización. La aplicación de producción podría cargar un inicializador ficticio, mientras que la aplicación de desarrollo podría cargar el inicializador real. Podría usar Unity/MEF

// Unity Dependency Injection Prop 
    [Dependency] 
    property IMyInitializer initializer; 

    protected override Seed(YourContextClass context) 
    { 
     initializer.Seed(context); 
    } 

Algo así.Luego, debe cambiar los inicializadores una vez que tenga la configuración de la base de datos en Producción, en la unidad ficticia, eso no haría nada.

16

Estoy un tanto de acuerdo con la respuesta Arthur Vickers, sin embargo, IMO Seed es para DbMigrations y no quiero que el método Seed compruebe todo todo el tiempo, p. Ej. Si tengo 4 migraciones, entonces tendría que probar de alguna manera qué datos se deben sembrar y, por lo menos, habrá 4 hits más en la base de datos. En caso de que todavía le gustaría tener el comportamiento de ejecutar el método de la semilla sólo cuando se aplican las migraciones, como yo, vine con mi propia implementación de la estrategia IDatabaseInitializer

public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration> 
    : IDatabaseInitializer<TContext> 
    where TContext : DbContext 
    where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new() 
{ 
    public virtual void InitializeDatabase(TContext context) 
    { 
     var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>())); 
     if (migratorBase.GetPendingMigrations().Any()) 
      migratorBase.Update(); 
    } 
} 
+1

Gracias, esto era exactamente lo que estaba buscando. – Jono

+1

Excelente solución, funciona como una magia. – sairfan

Cuestiones relacionadas