Entity Framework: Une Base De Données, Plusieurs DbContexts. Est-ce une mauvaise idée?

mon impression à ce jour a été qu'un DbContext est destiné à représenter votre base de données, et donc, si votre application utilise une base de données, vous voulez seulement un DbContext. Toutefois, certains collègues veulent subdiviser les zones fonctionnelles en classes distinctes de Dbcontexte. Je crois que ça vient d'un bon endroit -- un désir de garder le code propre -- mais ça semble volatile. 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.

donc je cherche A) des exemples concrets de pourquoi ce pourrait être une mauvaise idée, ou B) des assurances que tout va très bien se passer.

167
demandé sur Josh Schultz 2012-06-26 01:39:58

11 réponses

vous pouvez avoir plusieurs contextes pour une seule base de données. Il peut être utile par exemple si votre base de données contient plusieurs schémas de base de données et vous voulez traiter chacun d'eux comme une zone autonome séparée.

le problème est quand vous voulez utiliser le code d'abord pour créer votre base de données - seul le contexte unique dans votre application peut le faire. Le truc pour cela est habituellement un contexte supplémentaire contenant toutes vos entités qui est utilisé uniquement pour la création de base de données. Votre les contextes d'application réels ne contenant que des sous-ensembles de vos entités doivent avoir initialiseur de base de données défini à 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, il peut rendre votre conception beaucoup plus propre et séparer les différents domaines fonctionnels, mais il a ses coûts dans la complexité supplémentaire.

138
répondu Ladislav Mrnka 2012-06-25 22:35:30

ce fil vient de bouillonner sur StackOverflow et je voulais donc offrir une autre "B) assurance que tout cela sera très bien":)

je fais exactement cela par le biais du modèle de contexte limité DDD. J'ai écrit à ce sujet dans mon livre, cadre D'entité de programmation: DbContext et il est le point de mire d'un module de 50 minutes dans l'un de mes cours sur le Pluralsight - > http://pluralsight.com/training/Courses/TableOfContents/efarchitecture

47
répondu Julie Lerman 2016-10-18 22:31:25

Distiguishing contextes par le réglage par défaut schmema

dans EF6 vous pouvez avoir plusieurs contextes, il suffit de spécifier le nom du schéma de base de données par défaut dans la classe dérivée OnModelCreating de la méthode DbContext (où la configuration de L'API Fluent est). Cela fonctionnera dans EF6:

public partial class CustomerModel : DbContext
{   
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("Customer");

        // Fluent API configuration
    }   
}

cet exemple utilisera" client "comme préfixe pour vos tables de base de données (au lieu de"dbo"). Plus important encore, il préfixe également la ou les tables __MigrationHistory , par exemple Customer.__MigrationHistory . Vous pouvez donc avoir plus d'une table __MigrationHistory dans une seule base de données, une pour chaque contexte. Ainsi, les changements que vous apporterez à un contexte ne modifieront pas 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 la commande add-migration :

add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS



un petit mot sur la touche de contexte

, Selon cet article MSDN " Chapitre - Plusieurs Modèles de Ciblage de la Même Base de données " EF 6 serait probablement gérer la situation même si un seul MigrationHistory table existé, parce que dans la table il y a un ContextKey colonne de distinguer les migrations.

cependant je préfère avoir plus d'un MigrationHistory table en spécifiant le schéma par défaut comme expliqué ci-dessus.



utilisant des dossiers de migration séparés

dans un tel scénario, vous pourriez également vouloir travailler avec différents dossiers" Migration " dans votre projet. Vous pouvez configurer votre classe dérivée DbMigrationsConfiguration en conséquence en utilisant la propriété MigrationsDirectory :

internal sealed class ConfigurationA : DbMigrationsConfiguration<ModelA>
{
    public ConfigurationA()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations\ModelA";
    }
}

internal sealed class ConfigurationB : DbMigrationsConfiguration<ModelB>
{
    public ConfigurationB()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations\ModelB";
    }
}



résumé

tout compte fait, on peut dire que tout est bien séparé: contextes, dossiers de Migration dans le projet et tables dans la base de données.

je choisirais une telle solution, s'il y a des groupes d'entités qui font partie d'un sujet plus vaste, mais qui ne sont pas liées entre elles (via des clés étrangères).

si les groupes d'entités ne rien à faire les uns les autres, j'aurais créé une base de données distincte pour chacun d'entre eux et également accéder à différents projets, avec probablement un contexte unique de chaque projet.

38
répondu Martin 2016-06-22 13:18:48

je vais peser contre l'idée, avec l'expérience du monde réel pour sauvegarder mon vote.

j'ai été amené à une grande application qui avait cinq contextes pour une base de données unique. En fin de compte, nous avons fini par supprimer tous les contextes sauf pour un retour à un contexte unique.

au début, l'idée de contextes multiples semble être une bonne idée. Nous pouvons séparer nos accès de données en domaines et fournir plusieurs contextes légers propres. Sonne comme DDD, droit? Cela simplifierait notre accès aux données. Un autre argument est 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 se développait, plusieurs de nos tables partageaient des relations entre nos divers contextes. Par exemple, pour les requêtes relatives au tableau A dans le contexte 1, il fallait aussi joindre le tableau B dans le contexte 2.

cela nous a laissé avec quelques mauvais choix. On pourrait dupliquer les tables dans les différents contextes. Nous avons essayé ce. Cela a créé plusieurs problèmes de mappage, y compris une contrainte EF qui exige 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 commerciale interrogerait la moitié des ce qu'il faut de contexte 1 et l'autre moitié de contexte 2. Ceci a eu quelques problèmes majeurs. Au lieu d'effectuer une requête sur un même contexte, nous avons dû effectuer plusieurs requêtes dans différents contextes. Il y a là une véritable pénalité de performance.

En fin de compte, la bonne nouvelle est qu'il est facile de supprimer les multiples contextes. Le contexte se veut un objet léger. Donc je ne pense pas que la performance soit un bon argument pour des contextes multiples. Dans presque tous les cas, je crois qu'un seul contexte est plus simple, moins complexe, et fera mieux, et vous n'aurez pas à mettre en œuvre un tas de solutions de rechange pour le faire fonctionner.

j'ai pensé à une situation où plusieurs contextes pourraient être utiles. Un contexte séparé pourrait être utilisé pour résoudre un problème physique avec la base de données dans laquelle elle contient effectivement plus d'un domaine. Idéalement, un contexte serait un à un pour un domaine, ce qui serait un à une pour une base de données. En d'autres termes, si un ensemble de tableaux n'est en aucune façon relié aux autres tableaux d'une base de données Donnée, ils devraient probablement être retirés dans une base de données distincte. Je me rends compte que ce n'est pas toujours pratique. Mais si un ensemble de tableaux sont si différents que vous vous sentiriez à l'aise de les séparer dans une base de données séparée (mais vous choisissez de ne pas le faire) alors je pourrais voir le cas pour utiliser un contexte séparé, mais seulement parce qu'il y a en fait deux domaines séparés.

vos pensées m'intéressent.

34
répondu Francisco d'Anconia 2017-03-11 00:07:37

exemple Simple pour réaliser ce qui suit:

    ApplicationDbContext forumDB = new ApplicationDbContext();
    MonitorDbContext monitor = new MonitorDbContext();

juste portée des propriétés dans le contexte principal: (utilisé pour créer et maintenir le DB) Note: il suffit d'utiliser protégé: (entité n'est pas exposée ici)

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("QAForum", throwIfV1Schema: false)
    {

    }
    protected DbSet<Diagnostic> Diagnostics { get; set; }
    public DbSet<Forum> Forums { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Thread> Threads { get; set; }
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}

MonitorContext: Exposer entité séparée ici

public class MonitorDbContext: DbContext
{
    public MonitorDbContext()
        : base("QAForum")
    {

    }
    public DbSet<Diagnostic> Diagnostics { get; set; }
    // add more here
}

Modèle De Diagnostic:

public class Diagnostic
{
    [Key]
    public Guid DiagnosticID { get; set; }
    public string ApplicationName { get; set; }
    public DateTime DiagnosticTime { get; set; }
    public string Data { get; set; }
}

Si vous voulez, vous pouvez marquer toutes les entités protégées à l'intérieur de la principale ApplicationDbContext, puis créer des contextes supplémentaires si nécessaire pour chaque séparation de schémas.

ils utilisent tous la même chaîne de connexion, cependant ils utilisent des connexions séparées, donc ne croisent pas les transactions et être au courant des problèmes de verrouillage. Généralement votre conception de séparation donc cela ne devrait pas se produire de toute façon.

6
répondu Choco 2014-10-08 01:30:06

rappel: si vous combinez plusieurs contextes, assurez-vous de couper n coller toutes les fonctionnalités de votre RealContexts.OnModelCreating() dans votre unique CombinedContext.OnModelCreating() .

j'ai juste perdu du temps à chercher pourquoi mes relations de suppression en cascade n'étaient pas préservées seulement pour découvrir que je n'avais pas porté le code modelBuilder.Entity<T>()....WillCascadeOnDelete(); de mon contexte réel dans mon contexte combiné.

6
répondu Ilan 2016-06-09 11:08:26

mon instinct m'a dit la même chose quand je suis tombé sur cette conception.



Je travaille sur une base de code où il y a trois dbContexts pour une base de données. 2 des 3contextes DB dépendent de l'information de 1contexte DB parce qu'il sert les données administratives. Cette conception a placé 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 à dbcontexts. Au lieu de ce que vous êtes nécessaire à faire est de interrogez les deux dbcontexts séparés puis faire une jointure en mémoire ou itérer par les deux pour obtenir la combinaison des deux comme ensemble de résultats. Le problème avec cela est qu'au lieu de demander un jeu de résultats spécifique, vous chargez maintenant tous vos enregistrements dans la mémoire et faites ensuite une jointure contre les deux ensembles de résultats dans la mémoire. Il peut vraiment ralentir les choses.



Je voudrais poser la question " juste parce que vous pouvez, devriez-vous? "



Voir cet article pour le problème que je suis tombé sur lié à cette conception. L'expression LINQ spécifiée contient des références à des requêtes qui sont associées à des contextes différents

4
répondu Victor J. Garcia 2017-05-23 10:31:37

en code d'abord, vous pouvez avoir plusieurs DBContext et juste une base de données. Il suffit de spécifier la chaîne de connexion dans le constructeur.

public class MovieDBContext : DbContext
{
    public MovieDBContext()
        : base("DefaultConnection")
    {

    }
    public DbSet<Movie> Movies { get; set; }
}
2
répondu Daniel 2013-12-10 09:27:10

un autre peu de "sagesse". J'ai une base de données face à l'internet et une application interne. J'ai un contexte pour chaque face. Ça m'aide à garder une ségrégation disciplinée et sécurisée.

2
répondu Miguel Delgado 2015-02-10 05:24:52

inspiré par [l'Article 2013 de MSDN Mag de@JulieLerman] [1]

    public class ShippingContext : BaseContext<ShippingContext>
{
  public DbSet<Shipment> Shipments { get; set; }
  public DbSet<Shipper> Shippers { get; set; }
  public DbSet<OrderShippingDetail> Order { get; set; } //Orders table
  public DbSet<ItemToBeShipped> ItemsToBeShipped { get; set; }
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Ignore<LineItem>();
    modelBuilder.Ignore<Order>();
    modelBuilder.Configurations.Add(new ShippingAddressMap());
  }
}

public class BaseContext<TContext>
  DbContext where TContext : DbContext
{
  static BaseContext()
  {
    Database.SetInitializer<TContext>(null);
  }
  protected BaseContext() : base("DPSalesDatabase")
  {}
}   

" si vous faites un nouveau développement et que vous voulez laisser le Code créer ou migrer votre base de données à partir de vos classes, vous devrez créer un "uber-model" en utilisant un DbContext qui inclut toutes les classes et les relations nécessaires pour construire un modèle complet qui représente la base de données. Toutefois, ce contexte ne doit pas hériter de BaseContext."JL

1
répondu OzBob 2016-04-22 09:06:15

je veux partager un cas, où je pense que la possibilité d'avoir plusieurs DBContexts dans la même base de données fait du bon sens.

j'ai une solution avec deux bases de données. L'une concerne les données du domaine, à l'exception des informations sur les utilisateurs. L'autre est uniquement pour les informations de l'utilisateur. Cette division est principalement régie par le règlement général sur la Protection des données 151930920 de l'UE . En ayant deux bases de données, je peux librement déplacer les données du domaine (par exemple D'Azure à mon développement environnement) aussi longtemps que les données de l'utilisateur restent dans un endroit sûr.

maintenant pour la base de données des utilisateurs j'ai mis en œuvre deux schémas par L'intermédiaire de EF. Le premier est celui fourni par défaut par le cadre D'identité AspNet. L'autre est notre propre mise en œuvre de tout autre utilisateur. Je préfère cette solution à l'extension du schéma ApsNet, parce que je peux facilement gérer les changements futurs à L'identité AspNet et en même temps la séparation rend clair pour les programmeurs, que "notre propre utilisateur l'information " va dans le schéma d'utilisateur spécifique que nous avons défini.

0
répondu freilebt 2018-02-25 14:00:02