Mi impresión hasta la fecha ha sido que a DbContext
está destinado a representar su base de datos y, por lo tanto, si su aplicación usa una base de datos, solo querrá una DbContext
.
Sin embargo, algunos colegas quieren dividir las áreas funcionales en DbContext
clases separadas .
Creo que esto proviene de un buen lugar, un deseo de mantener el código más limpio, pero parece volátil. Mi instinto me dice que es una mala idea, pero desafortunadamente, mi instinto no es una condición suficiente para una decisión de diseño.
Entonces estoy buscando:
A) ejemplos concretos de por qué esto podría ser una mala idea;
B) asegura que todo saldrá bien.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
fuente
fuente
Respuestas:
Puede tener múltiples contextos para una sola base de datos. Puede ser útil, por ejemplo, si su base de datos contiene múltiples esquemas de base de datos y desea manejar cada uno de ellos como un área independiente.
El problema es cuando quiere usar el código primero para crear su base de datos; solo un contexto en su aplicación puede hacerlo. El truco para esto suele ser un contexto adicional que contiene todas sus entidades que se usa solo para la creación de bases de datos. Los contextos de aplicaciones reales que contienen solo subconjuntos de sus entidades deben tener inicializador de base de datos establecido en nulo.
Hay otros problemas que verá cuando use varios tipos de contexto, por ejemplo, tipos de entidades compartidas y su paso de un contexto a otro, etc. Generalmente es posible, puede hacer que su diseño sea mucho más limpio y separar diferentes áreas funcionales, pero tiene su costos en complejidad adicional.
fuente
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
funciona ahora.Escribí esta respuesta hace unos cuatro años y mi opinión no ha cambiado. Pero desde entonces ha habido desarrollos significativos en el frente de microservicios. Agregué notas específicas de microservicios al final ...
Sopesaré la idea, con experiencia en el mundo real para respaldar mi voto.
Fui llevado a una aplicación grande que tenía cinco contextos para una sola base de datos. Al final, terminamos eliminando todos los contextos, excepto uno, volviendo a un solo contexto.
Al principio, la idea de múltiples contextos parece una buena idea. Podemos separar nuestro acceso a datos en dominios y proporcionar varios contextos ligeros y limpios. Suena como DDD, ¿verdad? Esto simplificaría nuestro acceso a los datos. Otro argumento es para el rendimiento, ya que solo accedemos al contexto que necesitamos.
Pero en la práctica, a medida que nuestra aplicación creció, muchas de nuestras tablas compartieron relaciones en nuestros diversos contextos. Por ejemplo, las consultas a la tabla A en el contexto 1 también requerían unir la tabla B en el contexto 2.
Esto nos dejó con un par de malas elecciones. Podríamos duplicar las tablas en los diversos contextos. Intentamos esto. Esto creó varios problemas de mapeo, incluida una restricción de EF que requiere que cada entidad tenga un nombre único. Así que terminamos con entidades llamadas Persona1 y Persona2 en los diferentes contextos. Se podría argumentar que este fue un diseño deficiente de nuestra parte, pero a pesar de nuestros mejores esfuerzos, así es como nuestra aplicación realmente creció en el mundo real.
También intentamos consultar ambos contextos para obtener los datos que necesitábamos. Por ejemplo, nuestra lógica de negocios consultaría la mitad de lo que necesitaba del contexto 1 y la otra mitad del contexto 2. Esto tuvo algunos problemas importantes. En lugar de realizar una consulta en un contexto único, tuvimos que realizar múltiples consultas en diferentes contextos. Esto tiene una penalización de rendimiento real.
Al final, la buena noticia es que fue fácil eliminar los múltiples contextos. El contexto está destinado a ser un objeto ligero. Así que no creo que el rendimiento sea un buen argumento para múltiples contextos. En casi todos los casos, creo que un contexto único es más simple, menos complejo y probablemente funcionará mejor, y no tendrá que implementar un montón de soluciones para que funcione.
Pensé en una situación en la que múltiples contextos podrían ser útiles. Se podría usar un contexto separado para solucionar un problema físico con la base de datos en la que realmente contiene más de un dominio. Idealmente, un contexto sería uno a uno para un dominio, que sería uno a uno para una base de datos. En otras palabras, si un conjunto de tablas no está relacionado de ninguna manera con las otras tablas en una base de datos dada, probablemente deberían extraerse en una base de datos separada. Me doy cuenta de que esto no siempre es práctico. Pero si un conjunto de tablas es tan diferente que se sentiría cómodo separándolas en una base de datos separada (pero elige no hacerlo), entonces podría ver el caso para usar un contexto separado, pero solo porque en realidad hay dos dominios separados.
Con respecto a los microservicios, un contexto único todavía tiene sentido. Sin embargo, para los microservicios, cada servicio tendría su propio contexto, que incluye solo las tablas de la base de datos relevantes para ese servicio. En otras palabras, si el servicio x accede a las tablas 1 y 2, y el servicio y accede a las tablas 3 y 4, cada servicio tendría su propio contexto único que incluye tablas específicas para ese servicio.
Estoy interesado en tus pensamientos.
fuente
Este hilo acaba de aparecer en StackOverflow, por lo que quería ofrecer otra garantía "B) de que todo estará bien" :)
Estoy haciendo exactamente esto a través del patrón de contexto limitado DDD. Lo he escrito en mi libro, Programming Entity Framework: DbContext y es el foco de un módulo de 50 minutos dentro de uno de mis cursos en Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
fuente
Distinguir contextos estableciendo el esquema predeterminado
En EF6 puede tener múltiples contextos, solo especifique el nombre para el esquema de base de datos predeterminado en el
OnModelCreating
método de suDbContext
clase derivada (donde está la configuración Fluent-API). Esto funcionará en EF6:Este ejemplo utilizará "Cliente" como prefijo para las tablas de su base de datos (en lugar de "dbo"). Más importante aún, también prefijará las
__MigrationHistory
tablas, por ejemploCustomer.__MigrationHistory
. Por lo tanto, puede tener más de una__MigrationHistory
tabla en una sola base de datos, una para cada contexto. Por lo tanto, los cambios que realice para un contexto no afectarán al otro.Al agregar la migración, especifique el nombre completo de su clase de configuración (derivada de
DbMigrationsConfiguration
) como parámetro en eladd-migration
comando:Una palabra breve sobre la clave de contexto
De acuerdo con este artículo de MSDN " Capítulo - Múltiples modelos dirigidos a la misma base de datos ", EF 6 probablemente manejaría la situación incluso si solo
MigrationHistory
existiera una tabla, porque en la tabla hay una columna ContextKey para distinguir las migraciones.Sin embargo, prefiero tener más de una
MigrationHistory
tabla especificando el esquema predeterminado como se explicó anteriormente.Usar carpetas de migración separadas
En este caso, es posible que también desee trabajar con diferentes carpetas de "Migración" en su proyecto. Puede configurar su
DbMigrationsConfiguration
clase derivada en consecuencia utilizando laMigrationsDirectory
propiedad:Resumen
Con todo, puede decir que todo está limpio: Contextos, carpetas de migración en el proyecto y tablas en la base de datos.
Elegiría una solución así, si hay grupos de entidades que forman parte de un tema más amplio, pero que no están relacionadas (a través de claves externas) entre sí.
Si los grupos de entidades no tienen nada que hacer entre sí, crearía una base de datos separada para cada una de ellas y también accedería a ellas en diferentes proyectos, probablemente con un solo contexto en cada proyecto.
fuente
Ejemplo simple para lograr lo siguiente:
Solo alcance las propiedades en el contexto principal: (usado para crear y mantener la base de datos) Nota: Solo use protegido: (La entidad no está expuesta aquí)
MonitorContext: exponga una entidad separada aquí
Modelo de diagnóstico:
Si lo desea, puede marcar todas las entidades como protegidas dentro del ApplicationDbContext principal, luego cree contextos adicionales según sea necesario para cada separación de esquemas.
Todos usan la misma cadena de conexión, sin embargo, usan conexiones separadas, por lo que no cruza transacciones y tenga en cuenta los problemas de bloqueo. En general, diseña la separación, por lo que esto no debería suceder de todos modos.
fuente
DbSet<x>
definición. Lo hago en una clase parcial que coincide con lo que hace EF Designer.Recordatorio: si combina varios contextos, asegúrese de cortar y pegar todas las funcionalidades en sus varios
RealContexts.OnModelCreating()
en su únicoCombinedContext.OnModelCreating()
.Simplemente perdí el tiempo buscando por qué mis relaciones de eliminación en cascada no se conservaban solo para descubrir que no había portado el
modelBuilder.Entity<T>()....WillCascadeOnDelete();
código de mi contexto real a mi contexto combinado.fuente
OtherContext.OnModelCreating()
desde su contexto combinado?Mi instinto me dijo lo mismo cuando me encontré con este diseño.
Estoy trabajando en una base de código donde hay tres dbContexts en una base de datos. 2 de los 3 dbcontexts dependen de la información de 1 dbcontext porque sirve los datos administrativos. Este diseño ha impuesto restricciones sobre cómo puede consultar sus datos. Me encontré con este problema en el que no puedes unirte a través de dbcontexts. En cambio, lo que debe hacer es consultar los dos dbcontexts separados y luego hacer una unión en la memoria o iterar a través de ambos para obtener la combinación de los dos como un conjunto de resultados. El problema con eso es que, en lugar de consultar un conjunto de resultados específico, ahora está cargando todos sus registros en la memoria y luego haciendo una unión contra los dos conjuntos de resultados en la memoria. Realmente puede ralentizar las cosas.
Yo haría la pregunta "solo porque puedes, ¿deberías? "
Consulte este artículo para ver el problema que encontré relacionado con este diseño. La expresión LINQ especificada contiene referencias a consultas que están asociadas a diferentes contextos
fuente
Inspirado en [@JulieLerman 's DDD MSDN Mag Article 2013] [1]
fuente
En el código primero, puede tener múltiples DBContext y solo una base de datos. Solo tiene que especificar la cadena de conexión en el constructor.
fuente
Otro poco de "sabiduría". Tengo una base de datos para ambos, internet y una aplicación interna. Tengo un contexto para cada cara. Eso me ayuda a mantener una segregación disciplinada y segura.
fuente
Quiero compartir un caso, donde creo que la posibilidad de tener múltiples DBContexts en la misma base de datos tiene sentido.
Tengo una solución con dos bases de datos. Uno es para datos de dominio, excepto la información del usuario. El otro es únicamente para información del usuario. Esta división está impulsada principalmente por el Reglamento general de protección de datos de la UE . Al tener dos bases de datos, puedo mover libremente los datos del dominio (por ejemplo, de Azure a mi entorno de desarrollo) siempre que los datos del usuario permanezcan en un lugar seguro.
Ahora para la base de datos de usuario he implementado dos esquemas a través de EF. Uno es el predeterminado proporcionado por el marco de AspNet Identity. El otro es nuestro propio implementar cualquier otra cosa relacionada con el usuario. Prefiero esta solución a extender el esquema de ApsNet, porque puedo manejar fácilmente los cambios futuros a la identidad de AspNet y, al mismo tiempo, la separación deja en claro a los programadores que "nuestra propia información de usuario" va en el esquema de usuario específico que hemos definido .
fuente
Huh, pasé mucho tiempo en un problema con contextos de DB separados para cada esquema de DB, espero que ayude a alguien más ...
Recientemente comencé a trabajar en un proyecto que tenía una base de datos con 3 esquemas (primer enfoque de DB), uno de ellos para la gestión de usuarios. Había un contexto de base de datos andamio de cada esquema separado. Por supuesto, los usuarios también estaban relacionados con otros esquemas, por ejemplo. esquema KB tenía un tema de tabla, que había "creado por", "modificado por última vez por" etc. FK al esquema de identidad, usuario de tabla.
Estos objetos se cargaron por separado en C #, en primer lugar, el tema se cargó desde 1 contexto, luego los usuarios se cargaron a través de ID de usuario desde el otro contexto db, ¡no está bien, tienen que arreglar esto! (similar a usar múltiples dbcontexts en la misma base de datos con EF 6 )
Primero, intenté agregar las instrucciones FK que faltan del esquema de identidad al esquema KB, a EF modelBuilder en el contexto KB DB. Lo mismo que si hubiera solo 1 contexto, pero lo separé a 2.
No funcionó, porque el contexto kb db no tenía ninguna información sobre el objeto de usuario, postgres devolvió el error
relation "AppUsers" does not exist
. La instrucción Select no tenía información adecuada sobre el esquema, los nombres de campo, etc.Casi me di por vencido, pero luego noté un interruptor "-d" al ejecutar
dotnet ef dbcontext scaffold
. Es la abreviatura de -data-annotations: use atributos para configurar el modelo (cuando sea posible). Si se omite, solo se usa la API fluida. Con este modificador especificado, las propiedades del objeto se definieron no en el contexto dbOnModelCreating()
, sino en el propio objeto, con atributos.De esta manera, EF obtuvo información suficiente para generar una instrucción SQL adecuada con nombres y esquemas de campo adecuados.
TL; DR: los contextos de DB separados no manejan bien las relaciones (FK) entre ellos, cada contexto solo tiene información sobre sus propias entidades. Cuando se especifica la activación de "-data-annotations"
dotnet ef dbcontext scaffold
, estas informaciones no se almacenan en cada contexto por separado, sino en los objetos DB.fuente