EF 4.3 Auto-Migrations con múltiples DbContexts en una base de datos

Intento usar migraciones de EF 4.3 con múltiples DbContexts de primer código. Mi aplicación está separada en varios complementos, que posiblemente tengan su propio DbContext con respecto a su dominio. La aplicación debe usar una única base de datos sql.

Cuando bash migrar automáticamente los contextos en una base de datos vacía, esto solo tiene éxito en el primer contexto. En cualquier otro contexto, el AutomaticMigrationDataLossAllowed-Property se establece en true, pero luego intenta eliminar las tablas del anterior.

Entonces mi pregunta es:

  • ¿Cómo puedo decirle a la configuración de migración solo para cuidar las tablas definidas en su contexto correspondiente y dejar todas las demás en paz?
  • ¿Cuál es el flujo de trabajo correcto para manejar múltiples DbContexts con migración automática en una única base de datos?

¡Gracias!

Code First Migrations asume que solo hay una configuración de migraciones por base de datos (y un contexto por configuración).

Puedo pensar en dos posibles soluciones:

  1. Cree un contexto agregado que incluya todas las entidades de cada contexto y haga referencia a este contexto “super” de su clase de configuración de migraciones. De esta forma, todas las tablas se crearán en la base de datos del usuario, pero los datos solo estarán en los que hayan instalado complementos.

  2. Use bases de datos separadas para cada contexto. Si ha compartido entidades entre los contextos, agregue una migración personalizada y reemplace la llamada CreateTable(...) con una llamada Sql("CREATE VIEW ...") para obtener los datos de la base de datos “originaria” de la entidad.

Intentaría # 1 ya que mantiene todo en una sola base de datos. Puede crear un proyecto separado en su solución para contener sus migraciones y este contexto “súper”. Simplemente agregue el proyecto, haga referencia a todos los proyectos de sus complementos, cree un contexto que incluya todas las entidades, luego llame a Enable-Migrations en este nuevo proyecto. Las cosas deberían funcionar como se espera después de eso.

Esto es lo que puedes hacer. muy simple.

Puede crear clases de configuración para cada uno de sus contextos. p.ej

 internal sealed class Configuration1 : DbMigrationsConfiguration{ public Configuration1 (){ AutomaticMigrationsEnabled = false; MigrationsNamespace = "YourProject.Models.ContextNamespace1"; } } internal sealed class Configuration2 : DbMigrationsConfiguration{ public Configuration2 (){ AutomaticMigrationsEnabled = false; MigrationsNamespace = "YourProject.Models.ContextNamespace2"; } } 

Ahora agrega migración. No necesita habilitar la migración ya que ya lo hizo con los 2 clasificados anteriormente.

 Add-Migration -configuration Configuration1 Context1Init 

Esto creará un script de migración para context1. tu puedes repetir esto nuevamente para otros Contextos.

 Add-Migration -configuration Configuration2 Context2Init 

Para actualizar su base de datos

 Update-Database -configuration Configuration1 Update-Database -configuration Configuration2 

Esto se puede hacer en cualquier orden. Excepto que necesita asegurarse de que cada configuración se llame en secuencia.

Tengo un sitio de trabajo con contextos múltiples que usan migraciones. Sin embargo, necesita usar una base de datos separada por contexto, y todo es expulsado de * una clase de configuración en el espacio de nombres de Migraciones de su proyecto, por ejemplo, CompanyDbContext apunta a Company.sdf usando CompanyConfiguration. update-database -configurationtypename CompanyConfiguration . Otro LogDbContext apunta a Log.sdf usando LogConfiguration, etc.

Teniendo en cuenta estos trabajos, ¿ha intentado crear 2 contextos apuntando a la misma base de datos y diciéndole al modelbuilder que ignore la lista de tablas del otro contexto?

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Ignore(); // more of these } 

Como las migraciones funcionan con ModelBuilder, esto podría hacer el trabajo.

La alternativa mala es evitar el uso de Migraciones automáticas, generar una migración cada vez y luego examinar y eliminar manualmente las declaraciones no deseadas, y luego ejecutarlas, aunque no hay nada que te impida crear una herramienta simple que mira los contextos y las declaraciones generadas y hace la arreglos de migración para ti.

Ok, he estado luchando con esto por un día, y aquí hay una solución para aquellos que buscan la respuesta …

Supongo que la mayoría de las personas que leen esta publicación están aquí porque tienen una gran clase de DbContext con muchas propiedades DbSet <> y lleva mucho tiempo cargar. Probablemente pensaste, bueno, eso tiene sentido, debería dividir el contexto, ya que no usaré todos los conjuntos de bases de datos a la vez, y solo cargaré un contexto “Parcial” en función de la situación en la que necesito eso. Entonces los divide, solo para descubrir que las migraciones de Code First no respaldan su manera de pensar revolucionaria.

Así que su primer paso debe haber sido dividir los contextos, luego ha agregado la clase MigrationConfiguration para cada uno de los nuevos contextos, ha agregado las cadenas de conexión exactamente iguales a sus nuevas clases Context.

Luego, intenté ejecutar los contextos recién divididos uno por uno, haciendo Add-Migration Context1 y luego haciendo Update-Database -Verbose …

Todo parecía funcionar bien, pero luego observa que cada migración subsiguiente borró todas las tablas de la migración anterior y solo dejó las tablas desde la última migración.

Esto se debe a que el modelo de Migraciones actual espera Single DbContext por base de datos, y debe ser una coincidencia alternativa.

Lo que también probé, y alguien sugirió aquí haciendo eso, es crear un único SuperContext, que tenga todos los conjuntos de Db en él. Cree una única clase de configuración de migración y ejecútelo. Deje sus clases de contexto parcial en su lugar e intente crear una instancia y utilícelas. El EF se queja de que el modelo de respaldo ha cambiado. Nuevamente, esto se debe a que EF compara su contexto db parcial con la firma de contexto All-Sets que quedó de su migración de Super Contexto.

Este es un gran error en mi opinión.

En mi caso, decidí que el RENDIMIENTO es más importante que las migraciones. Entonces, lo que terminé haciendo es que, después de ejecutar el contexto Súper y tener todas las tablas en su lugar, ingresé a la base de datos y borré manualmente la tabla _MigrationHistory.

Ahora, puedo instanciar y usar mis contextos parciales sin que EF se queje al respecto. No encuentra la tabla MigrationHistory y simplemente continúa, lo que me permite tener una vista “parcial” de la base de datos.

El cambio, por supuesto, es que cualquier cambio en el modelo tendrá que propagarse manualmente a la base de datos, así que ten cuidado.

Aunque funcionó para mí.

Como se mencionó anteriormente por Brice, la solución más práctica es tener 1 super DbContext por aplicación / base de datos.

Tener que usar solo 1 DbContext para una aplicación completa parece ser una desventaja técnica y metodológica crucial, ya que afecta la modularidad, entre otras cosas. Además, si usa los servicios de datos de WCF, solo puede usar 1 servicio de datos por aplicación, ya que un servicio de datos puede asignar solo 1 DbContext. Entonces esto altera la architecture considerablemente.

En el lado positivo, una pequeña ventaja es que todo el código de migración relacionado con la base de datos está centralizado.

Me acabo de enterar de este problema y me di cuenta de que el motivo por el que los había dividido en diferentes contextos consistía simplemente en agrupar los modelos relacionados en fragmentos manejables y no por ninguna otra razón técnica. En cambio, he declarado mi contexto como una clase parcial y ahora diferentes archivos de código con diferentes modelos en ellos pueden agregar DbSets al DbContext.

De esta forma, la magia de la automigración aún funciona.

Lo tengo trabajando con migraciones manuales, pero no se puede degradar ya que no puede discriminar entre configuraciones en la tabla __MigrationHistory. Si bash y rebajar, trata las migraciones de las otras configuraciones como automáticas y, dado que no permite la pérdida de datos, falla. Sin embargo, solo lo usaremos para actualizar, por lo que funciona para nuestros propósitos.

Sin embargo, parece bastante omisión, estoy seguro de que no sería difícil respaldarlo siempre que no haya superposición entre los DbContexts.

Seguramente la solución debe ser una modificación por parte del equipo EntityFramework para cambiar la API para admitir la modificación directa de la tabla _MigrationHistory a un nombre de tabla de su elección, como _MigrationHistory_Context1, de modo que pueda manejar la modificación de entidades DbContext independientes. De esta forma, todos se tratan por separado, y depende del desarrollador asegurarse de que los nombres de las entidades no colisionen.

Parece que hay muchas personas que comparten mi opinión de que un DbContext duplicado con referencias al superconjunto de entidades es una manera falsa y no amigable para la empresa de hacer las cosas. Los DbContexts duplicados fallan miserablemente en soluciones modulares (prismas o similares).

Quiero que la gente sepa que la respuesta con esto a continuación es lo que funcionó para mí, pero con una advertencia: no use la línea MigrationsNamespace.

 internal sealed class Configuration1 : DbMigrationsConfiguration{ public Configuration1 (){ AutomaticMigrationsEnabled = false; MigrationsNamespace = "YourProject.Models.ContextNamespace1"; } } internal sealed class Configuration2 : DbMigrationsConfiguration{ public Configuration2 (){ AutomaticMigrationsEnabled = false; MigrationsNamespace = "YourProject.Models.ContextNamespace2"; } } 

Sin embargo, ya tenía las 2 bases de datos establecidas con sus propios contextos definidos, así que me encontré con un error que decía “El espacio de nombres YourProject.Models ya tiene definido ContextNamespace1”. Esto fue porque “MigrationsNamespace =” YourProject.Models.ContextNamespace2 “;” causaba que dbcontext se definiera en el espacio de nombres YourProjects.Models dos veces después de probar Init (una vez en el archivo Context1Init de migración y otra donde lo tenía definido anteriormente).

Entonces, descubrí que lo que tenía que hacer en ese punto era comenzar mi base de datos y las migraciones desde cero (afortunadamente no tenía los datos que necesitaba guardar) siguiendo las instrucciones aquí: http://pawel.sawicz.eu/entity -marchas de restablecimiento de marcos /

Luego cambié el código para NO incluir la línea MigrationsNamespace.

 internal sealed class Configuration1 : DbMigrationsConfiguration{ public Configuration1 (){ AutomaticMigrationsEnabled = false; } } internal sealed class Configuration2 : DbMigrationsConfiguration{ public Configuration2 (){ AutomaticMigrationsEnabled = false; } } 

Luego ejecuté nuevamente el comando Add-Migration -configuration Configuration1 Context1Init y la línea Update-Database -configuration Configuration1 nuevamente (para mi segundo contexto también), y finalmente, todo parece funcionar bien ahora.