DropCreateDatabaseIfModelChanges EF6 da como resultado System.InvalidOperationException: el modelo que respalda el contexto ha cambiado

.net c# entity-framework entity-framework-6

Pregunta

Después de migrar a Entity Framework 6, aparece un error al ejecutar pruebas unitarias en el servidor de compilación.

Estoy usando el inicializador DropCreateDatabaseIfModelChanges . Cuando lo cambio a MigrateDatabaseToLatestVersion todo funciona, pero quiero seguir con el inicializador anterior.

El error que estoy recibiendo es:

System.InvalidOperationException: System.InvalidOperationException: El modelo que respalda el contexto 'AppContext' ha cambiado desde que se creó la base de datos. Considere el uso de Code First Migrations para actualizar la base de datos ( http://go.microsoft.com/fwlink/?LinkId=238269 ) ..

Lo que es correcto, cambió, pero con el inicializador DropCreateDatabaseIfModelChanges , se debe recrear. ¿Algunas ideas?

EF está configurado en App.config. Aquí está la parte relevante:

<connectionStrings>
    <add name="AppContext" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=my.app.unittest;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
        <parameters>
            <parameter value="v11.0" />
        </parameters>
    </defaultConnectionFactory>
    <contexts>
        <context type="my.app.core.Data.AppContext, my.app.core">
            <databaseInitializer type="System.Data.Entity.DropCreateDatabaseIfModelChanges`1[[my.app.core.Data.AppContext, my.app.core]], EntityFramework" />
        </context>
    </contexts>
    <providers>
        <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
</entityFramework>

Respuesta popular

Bueno, parece que EF 6.0 introduce una nueva regla:

"Si DbContext está usando un Inicializador Y las migraciones están configuradas, lance una excepción al construir el modelo".

Hasta e incluyendo el EF 6 RC esto no se aplicó. La parte molesta es que "las migraciones están configuradas" se define por la implementación de una DbMigrationsConfiguration. No parece haber una manera de deshabilitar las migraciones en las pruebas mediante programación, si se implementa

Lo resolví de una manera muy similar a Sebastian Piu: tuve que deshacerme de la clase de Configuración de mis pruebas, pero no pude eliminarlo porque estamos usando Migraciones para nuestro proyecto principal. Argh!

Este fue mi código antes:

public class MyDbContext : DbDContext, IMyDbContext
{
  public IDbSet<Users> Users {get; set;}
  public IDbSet<Widgets> Widgets {get; set;}
}

// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
  public Configuration()
  {
    AutomaticMigrationsEnabled = false;
  }
}

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context) { }
}

Encontré la excepción System.InvalidOperationException cuando se estaba inicializando DbContext en mi código de prueba. Como la aplicación no utiliza ningún Inicializador, no hubo problemas al ejecutar la aplicación como antes. Esto solo rompió mis pruebas.

La solución (que se parece más a una solución a las cosas que faltan en EF) es segmentar el Initializer y DbMigrationsConfiguration para que solo se vea uno en un entorno de ejecución. Quiero que mis pruebas utilicen el Inicializador y quiero que mi aplicación utilice la DbMigrationsConfiguration. Esto podría hacerse de manera más limpia si DbContext tuviera una interfaz, pero lamentablemente solo implementa IObjectContextAdapter.

Primero hice mi resumen de DbContext:

public class MyDbContext : DbDContext, IMyDbContext
{
  public IDbSet<Users> Users {get; set;}
  public IDbSet<Widgets> Widgets {get; set;}
}

// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
  public Configuration()
  {
    AutomaticMigrationsEnabled = false;
  }
}

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context) { }
}

Luego derivé 2 clases:

public class MyDbContext : DbDContext, IMyDbContext
{
  public IDbSet<Users> Users {get; set;}
  public IDbSet<Widgets> Widgets {get; set;}
}

// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
  public Configuration()
  {
    AutomaticMigrationsEnabled = false;
  }
}

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context) { }
}

Tanto un MyDbContext como un MyTestDbContext son IMyDbContexts, por lo que su configuración de inyección de dependencia existente debería funcionar sin necesidad de cambios. Sólo probé Spring.NET.

Mi DbMigrationsConfiguration implementa el tipo derivado que NO es usado por las pruebas:

public class MyDbContext : DbDContext, IMyDbContext
{
  public IDbSet<Users> Users {get; set;}
  public IDbSet<Widgets> Widgets {get; set;}
}

// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
  public Configuration()
  {
    AutomaticMigrationsEnabled = false;
  }
}

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context) { }
}

Finalmente, el tipo de inicializador se movió al tipo de clase de prueba derivada:

public class MyDbContext : DbDContext, IMyDbContext
{
  public IDbSet<Users> Users {get; set;}
  public IDbSet<Widgets> Widgets {get; set;}
}

// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
  public Configuration()
  {
    AutomaticMigrationsEnabled = false;
  }
}

// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context) { }
}

Puedo confirmar que mis pruebas están pasando y mi aplicación (y Migraciones) sigue funcionando como antes.




Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué