entity-framework-4 - script - no migrations configuration type was found in the assembly
¿Por qué el paso de Migración EF de Entity Framework requiere una cadena de conexión a la base de datos? (4)
Estoy tratando de usar y entender las Migraciones de EF (usando EF 4.3.1, Código Primero). Para crear un nuevo cambio, tengo que usar un comando como este:
Add-Migration MyMigration
-ConnectionString "Data Source=.;Initial Catalog=mydb;"
-ConnectionProviderName "System.Data.SqlClient"
-StartUpProjectName MyWebsite
-ProjectName MyEF.Migrations
¿Por qué Add-Migration requiere datos de cadena de conexión? Update-Database
necesita uno, que tiene sentido. ¿Pero no tiene Add-Migration todo lo que necesita de DbContext y la Configuración?
No es simplemente una maravilla ociosa, es muy confuso darle una base de datos, porque tenemos una cosa de "tenencia múltiple" en la que la base de datos deseada es flexible y puede cambiar de una solicitud a otra, y mucho menos en tiempo de compilación estática. Entonces, si Add-Migration
realidad ESTÁ UTILIZANDO esa base de datos, tenemos un problema.
ACTUALIZACIÓN: Nos dimos por vencidos con EF Migrations y en su lugar estamos utilizando Fluent Migrator , y estamos contentos. Es mucho, mucho más rápido, incluso considerando el hecho de que tenemos que escribir algunas cosas dos veces (una para el objeto EF y otra para la migración), y no tiene los problemas que se analizan en esta pregunta.
OP escribió:
¿Pero no tiene Add-Migration todo lo que necesita de DbContext y la Configuración?
No, como se mencionó aquí, la parte del código del Diseñador para una migración manual (lo que se creó con add-migration
) contiene una instantánea del esquema de su base de datos.
Dicho esto, el hecho de que estés usando una cadena de conexión, etc., es muy extraño. EF normalmente lo implica desde su (s) clase (s) DbContext y Web.Config. En un proyecto donde tengo una sola base de datos y un solo DbContext, creo una clase de Configuración y agrego una migración manual con:
add-migration
No tengo que pasar ningún otro argumento de línea de comando. Eso está en EF 4.3.1: ¿tal vez estabas usando un CTP o una versión anterior, o simplemente malinterpretaste los documentos?
Si tengo múltiples DB o DbContexts, entonces tengo varias clases de Configuración y uso por ejemplo:
add-migration -conf Log
Que utiliza mi clase de Configuración y la cadena de conexión relacionada en Web.config para agregar una migración manual para esa base de datos / DbContext.
Aquí hay un ejemplo de código más largo de un simple DbContext destinado a almacenar registros (separado de la base de datos principal):
namespace MyProj.Models.Log
{
public class LogDb : DbContext
{
public DbSet<LogLine> LogLines { get; set; }
public DbSet<LogTag> LogTags { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public LogDb()
#if DEPLOYDB
: base("LogDeploy")
#else
: base()
#endif
{
}
}
namespace MyProj.Migrations
{
internal sealed class Log : DbMigrationsConfiguration<LogDb>
{
public Log()
{
AutomaticMigrationsEnabled = true;
}
}
}
En Web.Config:
<add name="LogDb" connectionString="Initial Catalog=Log;Data Source=./SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />
<add name="LogDeploy" connectionString="Initial Catalog=Log;Data Source=00.00.000.00,12345;User ID=sql;Password=xxx;Network Library=DBMSSOCN" providerName="System.Data.SqlClient" />
Así que en este ejemplo, tengo varias bases de datos, múltiples DbContexts. El LogDb utiliza una cadena de conexión diferente en Web.Config en función de si "DBDEPLOY" se define en el momento de la compilación; Si lo es, usa "LogDeploy". Si no, utiliza el valor predeterminado: la cadena de conexión con el mismo nombre que la clase, "LogDb". Esto me permite implementar fácilmente los cambios de la base de datos en un servidor desde mi máquina local, cambiando la configuración de mi proyecto, abriendo un puerto en la máquina de base de datos SQL y ejecutando:
> update-database -conf Log
en la consola del administrador de paquetes.
Sentí curiosidad al leer tu pregunta, así que encendí un Sql Server Profiler para echar un vistazo a lo que está sucediendo cuando se ejecuta la migración de adición. De hecho, se conecta a la base de datos y accede a la base de datos para verificar la tabla __MigrationHistory
.
Esto también se muestra en el mensaje de error generado al intentar crear una segunda migración basada en código sin ejecutar la primera:
No se puede generar una migración explícita porque están pendientes las siguientes migraciones explícitas: [201205291928386_foo]. Aplique las migraciones explícitas pendientes antes de intentar generar una nueva migración explícita.
Creo que el motor de migraciones utiliza el modelo serializado de la base de datos para calcular qué pasos de migración deberían incluirse en la nueva migración.
Según tengo entendido, la base de datos solo se utiliza como ayuda para la generación de código. Siempre que las distintas bases de datos que utilice sean compatibles con el modelo en el código, esto no debería ser un problema para usted.
Editar
Como @Ladislav Mrnka señala, se requiere una verificación con la base de datos si se mezclan migraciones automáticas y basadas en código. Cuando crea una nueva migración, debe incluir todo lo que haya cambiado en su modelo desde la última migración. Si está utilizando migraciones automáticas, estas no se rastrean en el código. Al calcular qué cambios incluir en la migración, la migración de la última ejecución se utiliza como base. La única forma de verificar esto es la base de datos, ya que las migraciones automáticas podrían estar activadas.
Si está ejecutando solo con migraciones basadas en código (que creo que es la única opción para mantener el control), entonces esa base de datos puede considerarse solo como una ayuda de generación de código. Mientras la compatibilidad del modelo esté garantizada en todas las bases de datos a las que se conecte, todo debería funcionar.
Vi este video de Rowan Miller en marzo de 2014: Migraciones - Under the Hood
En el video, Rowan explica que el comando Add-Migration
realiza varios pasos que incluyen un componente llamado EdmModelDiffer
. EdmModelDiffer
compara el modelo actual con un modelo anterior de la última migración (que está incrustado en el archivo resx de la migración anterior) y luego calcula los cambios necesarios en la base de datos.
Así que el componente EdmModelDiffer
necesita la conexión de la base de datos.
Los pasos descritos en el video son:
- Construir modelo actual a partir de código
- Obtener el modelo anterior de la última migración (almacenado como instantánea en un archivo resx)
- Calcular los cambios necesarios en la base de datos (realizados por
EdmModelDiffer
) - Generé el nuevo archivo de migración.
Teóricamente, se podría suponer que sería suficiente comparar ese modelo actual con el modelo de la última migración para generar la nueva migración. Pero mientras tanto, otras personas también podrían haber realizado cambios en la base de datos. Probablemente por eso también hay un chequeo contra la base de datos. Sin hacer esto, el archivo de migración resultante no tendría que ser correcto.
Mira también el segundo video llamado Migraciones - Entornos de equipo
Add-Migration
comprueba la existencia de la base de datos e interactúa con la tabla __MigrationHistory
. Como @Anders Abel mencionó, se usa para investigar migraciones pendientes y también para seleccionar modelos anteriores para encontrar realmente lo que ha cambiado. Esto es especialmente importante si agrega una migración explícita a la solución donde las migraciones automáticas están habilitadas.