Confusión sobre las migraciones automáticas de EF y la siembra-siembra cada inicio de programa


Recientemente cambié una aplicación de usar lo siguiente para dev:

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 anulado Seed(context) en DbMigrationsConfiguration usando la extensión AddOrUpdate donde estaba usando Add antes con seeding en la base de datos drop (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 al igual que la Semilla. Mi comportamiento esperado es comprobar si es necesaria una migración (comprobación entre bastidores para ver si el modelo coincide con la base de datos física), actualizar las tablas/columnas nuevas/eliminadas y solo ejecutar seed si algo ha cambiado.

En mis pruebas seed se ejecuta cada vez, lo cual es viable pero aparentemente ineficiente y no era lo que esperaba. Por desgracia, el MSDN la documentación es bastante limitada.

¿Estoy haciendo un mal uso de MigrateDatabaseToLatestVersion? ¿Hay alguna manera de obtener el comportamiento que espero (es decir, solo seed si hay un cambio de modelo) o simplemente debo cambiar mi método seed para esperar que se ejecute cada lanzamiento de la aplicación?

Author: shox, 2012-05-30

3 answers

El hecho de que el método Seed solo se ejecutara cuando la base de datos cambiara era bastante limitante para los inicializadores de base de datos que se incluían en EF 4.1. Era limitante porque a veces necesitabas actualizar los datos semilla sin cambiar la base de datos, pero para que eso sucediera tenías que hacer que pareciera que la base de datos había cambiado artificialmente.

Con las migraciones el uso de Seed se volvió un poco diferente porque ya no se podía asumir que la base de datos estaba empezando vacía that punto de Migraciones, después de todo. Por lo tanto, un método Semilla en Migraciones tiene que asumir que la base de datos existe y puede que ya tenga datos en ella, pero que los datos pueden necesitar ser actualizados 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 escribirse para tener en cuenta los datos existentes, lo que significa que realmente no hay necesidad de perpetuar las limitaciones del método de semilla EF 4.1 de tal manera que usted tendría para que pareciera que la base de datos había cambiado solo para que se ejecutara 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 imlementan las semillas, ya que necesita manejar el caso en el que los datos ya están presentes de todos modos.

Si causa problemas de perf porque tiene muchos datos de semilla, generalmente es fácil agregar comprobaciones en el método de semilla que consultan la base de datos para determinar cuánto trabajo se necesita hacer antes de hacerlo.

 60
Author: Arthur Vickers,
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
2012-05-31 00:39:07

Estoy un poco de acuerdo con Arthur Vickers respuesta, sin embargo IMO Seed es para DbMigrations y no quiero que el método Seed para comprobar todo cada vez, por ejemplo, Si tengo 4 migraciones entonces tendría que probar de alguna manera que los datos deben ser sembrados y que será 4 más base de datos hits al menos. En caso de que todavía le gustaría tener el comportamiento de ejecutar el método Seed solo cuando se aplican 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();
    }
}
 16
Author: Guillermo Ruffino,
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-05-23 12:02:43

Otra opción podría ser cargar una clase de inicializador de base de datos personalizada en tiempo de ejecución dentro del método seed. 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. Puedes usar Unity / MEF

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

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

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

 2
Author: Gary Gaughan-Smith,
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
2012-10-14 12:41:03