88 votes

Quand dois-je créer un nouveau DbContext() ?

J'utilise actuellement un DbContext similaire à celui-ci :

namespace Models
{
    public class ContextDB: DbContext
    {

        public DbSet<User> Users { get; set; }
        public DbSet<UserRole> UserRoles { get; set; }

        public ContextDB()
        {

        }
    }
}

J'utilise ensuite la ligne suivante en haut de l'écran de l'application TOUTES mes contrôleurs qui ont besoin d'accéder à la base de données. Je l'utilise également dans ma classe UserRepository qui contient toutes les méthodes relatives à l'utilisateur (comme obtenir l'utilisateur actif, vérifier quels rôles il a, etc ) :

ContextDB _db = new ContextDB();

En y réfléchissant, il y a des occasions où un visiteur peut avoir plusieurs DbContexts actifs, par exemple s'il visite un contrôleur qui utilise le UserRepository, ce qui n'est peut-être pas la meilleure des idées.

Quand dois-je créer un nouveau DbContext ? Ou bien, devrais-je avoir un contexte global qui est transmis et réutilisé à tous les endroits ? Cela n'entraînerait-il pas une baisse des performances ? Les suggestions d'autres façons de procéder sont également les bienvenues.

87voto

Benjamin Gale Points 5390

J'utilise un contrôleur de base qui expose un DataBase à laquelle les contrôleurs dérivés peuvent accéder.

public abstract class BaseController : Controller
{
    public BaseController()
    {
        Database = new DatabaseContext();
    }

    protected DatabaseContext Database { get; set; }

    protected override void Dispose(bool disposing)
    {
        Database.Dispose();
        base.Dispose(disposing);
    }
}

Tous les contrôleurs de mon application dérivent de BaseController et sont utilisés comme ceci :

public class UserController : BaseController
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(Database.Users.OrderBy(p => p.Name).ToList());
    }
}

Maintenant, pour répondre à vos questions :

Quand dois-je créer un nouveau DbContext / dois-je avoir sur que je fais circuler ?

Le contexte doit être créé par demande. Créez le contexte, faites ce que vous avez besoin de faire avec lui puis débarrassez-vous-en. Avec la solution de la classe de base que j'utilise, vous n'avez à vous soucier que de l'utilisation du contexte.

N'essayez pas d'avoir un contexte global (ce n'est pas ainsi que fonctionnent les applications web).

Puis-je avoir un Contexte global que je réutilise dans tous les endroits ?

Non, si vous conservez un contexte, il suivra toutes les mises à jour, les ajouts, les suppressions, etc., ce qui ralentira votre application et pourrait même provoquer l'apparition de bogues assez subtils dans votre application.

Vous devriez probablement choisir soit d'exposer votre référentiel ou votre Contexte à votre contrôleur mais pas les deux. Le fait que deux contextes soient accessibles à partir de la même méthode va entraîner des bogues s'ils ont tous deux des idées différentes sur l'état actuel de l'application.

Personnellement, je préfère exposer DbContext directement, car la plupart des exemples de référentiels que j'ai vus ne sont que de minces enveloppes autour de DbContext de toute façon.

Cela entraîne-t-il une baisse des performances ?

La première fois qu'un DbContext La création d'un contexte est assez coûteuse, mais une fois que cela a été fait, beaucoup d'informations sont mises en cache, de sorte que les instanciations suivantes sont beaucoup plus rapides. Vous êtes plus susceptibles de rencontrer des problèmes de performance en conservant un contexte que d'en instancier un à chaque fois que vous avez besoin d'accéder à votre base de données.

Comment les autres font-ils ?

Ça dépend.

Certaines personnes préfèrent utiliser un cadre d'injection de dépendances pour transmettre une instance concrète de leur contexte à leur contrôleur lors de sa création. Les deux options sont bonnes. La mienne est plus appropriée pour une application à petite échelle où vous savez que la base de données spécifique utilisée ne va pas changer.

certains peuvent prétendre que vous ne peut pas savent cela et c'est pourquoi la méthode d'injection de dépendances est meilleure car elle rend votre application plus résistante aux changements. Mon opinion à ce sujet est que cela ne changera probablement pas (le serveur SQL et Entity Framework ne sont guère obscurs) et que mon temps est mieux employé à écrire le code qui est spécifique à mon application.

14voto

Ravior Points 66

J'essaie de répondre à partir de ma propre expérience.

1. Quand dois-je créer un nouveau DbContext / dois-je avoir un contexte global que je fais circuler ?

Le contexte doit être injecté par l'injection de dépendances et ne doit pas être instancié par vous-même. La meilleure pratique consiste à le créer comme un service scopé par l'injection de dépendances. (Voir ma réponse à la question 4)

Veuillez également envisager l'utilisation d'une structure d'application en couches appropriée, telle que Contrôleur > BusinessLogic > Référentiel. Dans ce cas, ce n'est pas le contrôleur qui reçoit le contexte de la base de données mais le référentiel. Obtenir l'injection / l'instanciation d'un db-context dans un contrôleur m'indique que l'architecture de votre application mélange de nombreuses responsabilités en un seul endroit, ce que - en toutes circonstances - je ne peux pas recommander.

2. Puis-je avoir un Contexte global que je réutilise dans tous les endroits ?

Oui, vous. peut mais la question devrait être " Devrait J'ai..." -> NON. Le contexte est censé être utilisé pour chaque demande de modification de votre référentiel, puis il disparaît à nouveau.

3. Cela entraîne-t-il une baisse des performances ?

Oui, car le DBContext n'est tout simplement pas fait pour être global. Il stocke toutes les données qui y ont été saisies ou interrogées jusqu'à ce qu'il soit détruit. Cela signifie qu'un contexte global deviendra de plus en plus grand, que les opérations sur ce contexte seront de plus en plus lentes, jusqu'à ce que vous obteniez des exceptions de mémoire ou que vous mouriez d'âge parce que tout s'est ralenti.

Vous obtiendrez également des exceptions et de nombreuses erreurs lorsque plusieurs threads accèdent au même contexte en même temps.

4. Comment les autres font-ils ?

DBContext injecté via l'injection de dépendances par une fabrique ; scoped :

services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));

J'espère que mes réponses vous seront utiles.

2voto

Abolfazl Points 860

Du point de vue de la performance, DbContext devrait être créé just Par exemple, lorsque vous avez besoin d'une liste d'utilisateurs dans votre couche d'activité, vous créez une instance de votre DbContext et vous l'ajoutez à la liste des utilisateurs. immediately dispose quand votre travail est terminé

using (var context=new DbContext())
{
    var users=context.Users.Where(x=>x.ClassId==4).ToList();
}

context sera éliminée après avoir quitté Using Bloc.

Mais que se passe-t-il si vous ne l'éliminez pas immédiatement ?
DbContext est un cache dans l'essence et plus vous faites de requêtes, plus de blocs de mémoire seront occupés.
Il sera beaucoup plus perceptible en cas de concurrent requests En fonction de votre application, dans ce cas, chaque milliseconde d'occupation d'un bloc de mémoire serait essentielle, sans parler d'une seconde.
Plus vous reportez la destruction d'objets inutiles, plus votre application risque de se planter !

Bien sûr, dans certains cas, vous devez conserver votre DbContext et l'utiliser dans une autre partie de votre code mais dans la même Request Context .

Je vous renvoie au lien suivant pour obtenir plus d'informations sur la gestion de l'environnement. DbContext :
dbcontext Portée

1voto

Vous devez disposer du contexte immédiatement après chaque opération Save(). Sinon, chaque sauvegarde ultérieure prendra plus de temps. J'avais un projet qui créait et sauvegardait des entités de base de données complexes dans un cycle. À ma grande surprise, l'opération est devenue trois fois plus rapide après que j'ai déplacé

using (var ctx = new MyContext()){...}

à l'intérieur du cycle.

0voto

Andrew Points 1

Pour l'instant, j'essaie cette approche, qui évite d'instancier le contexte lorsque vous appelez des actions qui ne l'utilisent pas.

public abstract class BaseController : Controller
{
    public BaseController() { }

    private DatabaseContext _database;
    protected DatabaseContext Database
    {
        get
        {
            if (_database == null)
                _database = new DatabaseContext();
            return _database;
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (_database != null)
            _database.Dispose();
        base.Dispose(disposing);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X