À ce jour, j'ai l'impression que a DbContext
est censé représenter votre base de données, et donc, si votre application utilise une seule base de données, vous n'en voudriez qu'une DbContext
.
Cependant, certains collègues souhaitent diviser les domaines fonctionnels en DbContext
classes distinctes .
Je crois que cela vient d'un bon endroit - un désir de garder le code plus propre - mais il semble volatil. Mon instinct me dit que c'est une mauvaise idée, mais malheureusement, mon intuition n'est pas une condition suffisante pour une décision de conception.
Je recherche donc:
A) des exemples concrets de la raison pour laquelle cela pourrait être une mauvaise idée;
B) l'assurance que tout cela fonctionnera très bien.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
la source
la source
Réponses:
Vous pouvez avoir plusieurs contextes pour une seule base de données. Cela peut être utile, par exemple, si votre base de données contient plusieurs schémas de base de données et que vous souhaitez gérer chacun d'eux comme une zone autonome distincte.
Le problème est lorsque vous souhaitez d'abord utiliser du code pour créer votre base de données - seul un contexte unique dans votre application peut le faire. L'astuce pour cela est généralement un contexte supplémentaire contenant toutes vos entités qui est utilisé uniquement pour la création de base de données. Vos réels contextes d'application ne contenant que des sous-ensembles de vos entités doivent avoir un initialiseur de base de données défini sur null.
Il y a d'autres problèmes que vous verrez lors de l'utilisation de plusieurs types de contexte - par exemple, les types d'entités partagées et leur passage d'un contexte à un autre, etc. En général, il est possible, cela peut rendre votre conception beaucoup plus propre et séparer différents domaines fonctionnels, mais il a ses coûts en complexité supplémentaire.
la source
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
fonctionne maintenant.J'ai écrit cette réponse il y a environ quatre ans et mon opinion n'a pas changé. Mais depuis lors, il y a eu des développements importants sur le front des micro-services. J'ai ajouté des notes spécifiques aux micro-services à la fin ...
Je vais peser contre l'idée, avec une expérience du monde réel pour appuyer mon vote.
J'ai été amené à une grande application qui avait cinq contextes pour une seule base de données. En fin de compte, nous avons fini par supprimer tous les contextes, sauf un - revenir à un seul contexte.
Au début, l'idée de contextes multiples semble être une bonne idée. Nous pouvons séparer notre accès aux données en domaines et fournir plusieurs contextes propres et légers. Cela ressemble à DDD, non? Cela simplifierait notre accès aux données. Un autre argument est pour la performance en ce sens que nous n'accédons qu'au contexte dont nous avons besoin.
Mais dans la pratique, au fur et à mesure que notre application grandissait, bon nombre de nos tables partageaient des relations dans nos divers contextes. Par exemple, les requêtes vers la table A dans le contexte 1 nécessitent également de rejoindre la table B dans le contexte 2.
Cela nous a laissé quelques mauvais choix. Nous pourrions dupliquer les tableaux dans les différents contextes. Nous avons essayé cela. Cela a créé plusieurs problèmes de mappage, y compris une contrainte EF qui nécessite que chaque entité ait un nom unique. Nous nous sommes donc retrouvés avec des entités nommées Person1 et Person2 dans les différents contextes. On pourrait dire que c'était une mauvaise conception de notre part, mais malgré nos meilleurs efforts, c'est ainsi que notre application a réellement grandi dans le monde réel.
Nous avons également essayé d'interroger les deux contextes pour obtenir les données dont nous avions besoin. Par exemple, notre logique métier interrogerait la moitié de ce dont elle avait besoin dans le contexte 1 et l'autre moitié dans le contexte 2. Cela posait quelques problèmes majeurs. Au lieu d'exécuter une requête sur un seul contexte, nous avons dû effectuer plusieurs requêtes dans différents contextes. Cela a une vraie pénalité de performance.
Au final, la bonne nouvelle est qu'il a été facile de supprimer les multiples contextes. Le contexte est destiné à être un objet léger. Je ne pense donc pas que la performance soit un bon argument pour plusieurs contextes. Dans presque tous les cas, je crois qu'un seul contexte est plus simple, moins complexe et fonctionnera probablement mieux, et vous n'aurez pas à mettre en œuvre un tas de solutions pour le faire fonctionner.
J'ai pensé à une situation où plusieurs contextes pourraient être utiles. Un contexte distinct pourrait être utilisé pour résoudre un problème physique avec la base de données dans laquelle il contient en fait plus d'un domaine. Idéalement, un contexte serait un à un vers un domaine, qui serait un à un vers une base de données. En d'autres termes, si un ensemble de tables n'a aucun lien avec les autres tables d'une base de données donnée, elles devraient probablement être extraites dans une base de données distincte. Je me rends compte que ce n'est pas toujours pratique. Mais si un ensemble de tables est si différent que vous vous sentiriez à l'aise de les séparer dans une base de données distincte (mais vous choisissez de ne pas le faire), je pourrais voir le cas pour utiliser un contexte séparé, mais uniquement parce qu'il y a en fait deux domaines distincts.
En ce qui concerne les micro-services, un seul contexte a encore du sens. Cependant, pour les micro-services, chaque service aurait son propre contexte qui ne comprend que les tables de base de données pertinentes pour ce service. En d'autres termes, si le service x accède aux tables 1 et 2, et le service y accède aux tables 3 et 4, chaque service aurait son propre contexte unique qui inclut des tables spécifiques à ce service.
Je suis intéressé par vos pensées.
la source
Ce fil vient de bouillonner sur StackOverflow et je voulais donc offrir une autre "B) assurance que tout ira bien" :)
Je fais exactement cela au moyen du modèle de contexte délimité DDD. J'ai écrit à ce sujet dans mon livre, Programming Entity Framework: DbContext et c'est l'objet d'un module de 50 minutes dans l'un de mes cours sur Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
la source
Distinguer les contextes en définissant le schéma par défaut
Dans EF6, vous pouvez avoir plusieurs contextes, spécifiez simplement le nom du schéma de base de données par défaut dans la
OnModelCreating
méthode de votreDbContext
classe dérivée (où se trouve la configuration Fluent-API). Cela fonctionnera dans EF6:Cet exemple utilise "Customer" comme préfixe pour vos tables de base de données (au lieu de "dbo"). Plus important encore, il préfixera également les
__MigrationHistory
tables, par exempleCustomer.__MigrationHistory
. Vous pouvez donc avoir plusieurs__MigrationHistory
tables dans une seule base de données, une pour chaque contexte. Ainsi, les modifications que vous apportez à un contexte ne joueront pas avec l'autre.Lors de l'ajout de la migration, spécifiez le nom complet de votre classe de configuration (dérivé de
DbMigrationsConfiguration
) comme paramètre dans laadd-migration
commande:Un petit mot sur la touche contextuelle
Selon cet article MSDN " Chapitre - Plusieurs modèles ciblant la même base de données " EF 6 gérerait probablement la situation même si une seule
MigrationHistory
table existait, car dans la table il y a une colonne ContextKey pour distinguer les migrations.Cependant, je préfère avoir plus d'une
MigrationHistory
table en spécifiant le schéma par défaut comme expliqué ci-dessus.Utilisation de dossiers de migration distincts
Dans un tel scénario, vous pouvez également vouloir travailler avec différents dossiers de «migration» dans votre projet. Vous pouvez configurer votre
DbMigrationsConfiguration
classe dérivée en conséquence à l'aide de laMigrationsDirectory
propriété:Résumé
Dans l'ensemble, vous pouvez dire que tout est parfaitement séparé: Contextes, dossiers de migration dans le projet et tables dans la base de données.
Je choisirais une telle solution, s'il existe des groupes d'entités qui font partie d'un sujet plus vaste, mais qui ne sont pas liés (via des clés étrangères) les uns aux autres.
Si les groupes d'entités n'ont rien à faire les uns avec les autres, je créerais une base de données distincte pour chacun d'eux et y accèderais également dans différents projets, probablement avec un seul contexte dans chaque projet.
la source
Exemple simple pour réaliser ce qui suit:
Étendez simplement les propriétés dans le contexte principal: (utilisé pour créer et maintenir la base de données) Remarque: Utilisez simplement protected: (l'entité n'est pas exposée ici)
MonitorContext: exposez ici une entité distincte
Modèle de diagnostic:
Si vous le souhaitez, vous pouvez marquer toutes les entités comme protégées dans le ApplicationDbContext principal, puis créer des contextes supplémentaires selon les besoins pour chaque séparation des schémas.
Ils utilisent tous la même chaîne de connexion, mais ils utilisent des connexions distinctes, donc ne faites pas de transactions croisées et soyez conscient des problèmes de verrouillage. Généralement, vous concevez la séparation, cela ne devrait donc pas se produire de toute façon.
la source
DbSet<x>
définition manuellement . Je fais cela dans une classe partielle correspondant à ce que fait EF Designer.Rappel: Si vous combinez plusieurs contextes, assurez-vous de couper et coller toutes les fonctionnalités de vos différents
RealContexts.OnModelCreating()
dans votre singleCombinedContext.OnModelCreating()
.J'ai juste perdu du temps à chercher pourquoi mes relations de suppression en cascade n'étaient pas conservées uniquement pour découvrir que je n'avais pas porté le
modelBuilder.Entity<T>()....WillCascadeOnDelete();
code de mon contexte réel dans mon contexte combiné.la source
OtherContext.OnModelCreating()
partir de votre contexte combiné?Mon instinct m'a dit la même chose lorsque je suis tombé sur ce design.
Je travaille sur une base de code où il y a trois dbContexts dans une base de données. 2 des 3 dbcontexts dépendent des informations de 1 dbcontext car il sert les données administratives. Cette conception a imposé des contraintes sur la façon dont vous pouvez interroger vos données. J'ai rencontré ce problème où vous ne pouvez pas vous joindre à travers dbcontexts. Au lieu de cela, vous devez interroger les deux dbcontexts séparés, puis faire une jointure en mémoire ou parcourir les deux pour obtenir la combinaison des deux en tant qu'ensemble de résultats. Le problème avec cela est qu'au lieu d'interroger un ensemble de résultats spécifique, vous chargez maintenant tous vos enregistrements en mémoire, puis effectuez une jointure contre les deux ensembles de résultats en mémoire. Cela peut vraiment ralentir les choses.
Je poserais la question "juste parce que vous le pouvez, n'est-ce pas? "
Voir cet article pour le problème que j'ai rencontré concernant cette conception. L'expression LINQ spécifiée contient des références à des requêtes associées à différents contextes
la source
Inspiré par [@JulieLerman's DDD MSDN Mag Article 2013] [1]
la source
Dans le code d'abord, vous pouvez avoir plusieurs DBContext et une seule base de données. Il vous suffit de spécifier la chaîne de connexion dans le constructeur.
la source
Encore un peu de "sagesse". J'ai une base de données faisant face à la fois à Internet et à une application interne. J'ai un contexte pour chaque visage. Cela m'aide à maintenir une ségrégation disciplinée et sécurisée.
la source
Je veux partager un cas, où je pense que la possibilité d'avoir plusieurs DBContextes dans la même base de données est logique.
J'ai une solution avec deux bases de données. L'une concerne les données de domaine, à l'exception des informations utilisateur. L'autre est uniquement destiné aux informations utilisateur. Cette division est principalement tirée par le règlement général de l'UE sur la protection des données . En ayant deux bases de données, je peux déplacer librement les données du domaine (par exemple, d'Azure vers mon environnement de développement) tant que les données utilisateur restent dans un endroit sécurisé.
Maintenant, pour la base de données utilisateur, j'ai mis en œuvre deux schémas via EF. L'un est celui par défaut fourni par le framework d'identité AspNet. L'autre est notre propre implémentation de tout ce qui concerne l'utilisateur. Je préfère cette solution à l'extension du schéma ApsNet, car je peux facilement gérer les modifications futures de l'identité AspNet et en même temps, la séparation indique clairement aux programmeurs que "nos propres informations utilisateur" vont dans le schéma utilisateur spécifique que nous avons défini. .
la source
Huh, a passé pas mal de temps sur un problème avec des contextes de base de données distincts pour chaque schéma de base de données, j'espère que cela aidera quelqu'un d'autre ...
J'ai récemment commencé à travailler sur un projet qui avait une base de données avec 3 schémas (DB première approche), l'un d'eux pour la gestion des utilisateurs. Il y avait un contexte DB échafaudé de chaque schéma distinct. Bien sûr, les utilisateurs étaient également liés à d'autres schémas, par exemple. le schéma KB avait un sujet de table, qui avait "créé par", "modifié en dernier par" etc. FK au schéma d'identité, utilisateur de la table.
Ces objets ont été chargés séparément en C #, tout d'abord, le sujet a été chargé à partir d'un contexte, puis les utilisateurs ont été chargés via les ID utilisateur de l'autre contexte db - pas sympa, il faut résoudre ce problème! (similaire à l' utilisation de plusieurs dbcontexts dans la même base de données avec EF 6 )
Tout d'abord, j'ai essayé d'ajouter des instructions FK manquantes du schéma d'identité au schéma KB, à EF modelBuilder dans le contexte KB DB. Comme s'il n'y avait qu'un seul contexte, mais je l'ai séparé en 2.
Cela n'a pas fonctionné, car le contexte kb db ne contenait aucune information sur l'objet utilisateur, postgres a renvoyé une erreur
relation "AppUsers" does not exist
. L'instruction Select ne contenait pas d'informations appropriées sur le schéma, les noms de champ, etc.J'ai presque abandonné, mais j'ai remarqué un interrupteur "-d" lors de l'exécution
dotnet ef dbcontext scaffold
. Son abréviation pour -data-annotations - Utilisez des attributs pour configurer le modèle (si possible). S'il est omis, seule l'API courante est utilisée. Avec ce commutateur spécifié, les propriétés des objets ont été définies non pas dans le contexte dbOnModelCreating()
, mais plutôt sur l'objet lui-même, avec des attributs.De cette façon, EF a obtenu suffisamment d'informations pour générer une instruction SQL appropriée avec des noms de champ et des schémas appropriés.
TL; DR: les contextes de base de données séparés ne gèrent pas bien les relations (FK) entre eux, chaque contexte n'a que des informations sur ses propres entités. Lorsque vous spécifiez le paramètre "-data-annotations"
dotnet ef dbcontext scaffold
, ces informations ne sont pas stockées dans chaque contexte distinct, mais sur les objets DB eux-mêmes.la source