web-dev-qa-db-fra.com

EF Core DBContext dans une application d'API multithreaded

TL; DR Comment puis-je utiliser l'application d'entité dans une application d'API de base multithreaded .NET, même si DBContext n'est pas threadsafe?

Le contexte

Je travaille sur une application d'API .Net Core exposant plusieurs interfaces reposantes qui accèdent à la base de données et lisez les données à partir de celui-ci, tout en exécutant plusieurs fois plus de chronométrages, en tant que threads de travail en arrière-plan qui sondent régulièrement des autres Webservices et les stocker dans la base de données.

Je suis conscient du fait que dbcontext n'est pas threadsafe. J'ai lu beaucoup de documents, de poteaux de blogs et de réponses ici sur Stackoverflow, et je pourrais trouver beaucoup de réponses (partiellement contradictoires) pour cela, mais aucune "meilleure pratique" réelle lorsque vous travaillez également avec DI.

Choses que j'ai essayé

En utilisant la valeur par défaut ServiceLifetime.Scoped via la méthode d'extension AddDbContext donne des exceptions en raison des conditions de course.

Je ne veux pas travailler avec des serrures (par exemple, sémaphore), car les réciproques évidents sont:

  • le code est pollué avec des verrous et essayer/attraper/enfin pour libérer en toute sécurité les serrures
  • cela ne semble pas vraiment "robuste", c'est-à-dire lorsque j'oublie de verrouiller une région qui accède à DBContext.
  • il semble redondant et "non naturel" de synchroniser artificiellement l'accès à la base de données DB dans l'application lorsque vous travaillez avec une base de données qui gère également des connexions et un accès simultanés

Ne pas injecter MyDbContext mais DbContextOptions<MyDbContext> Au lieu de cela, construire le contexte uniquement lorsque j'ai besoin d'accéder à la base de données, à l'aide d'une instruction using à l'éliminer immédiatement après que la lecture/écriture semble avoir une telle utilisation de la ressource et de nombreuses ouvertures/fermeture de la connexion.

Question

Je suis vraiment perplexe: comment cela peut-il être vrai?

Je ne pense pas que mon usecase est super spécial - peupler la DB à partir d'un ouvrier d'arrière-plan et en l'interrogeant de la couche d'API Web - il devrait donc y avoir un moyen significatif de le faire avec EF Core.

Merci beaucoup!

7
Philip Daubmeier

Une autre approche pour créer son propre dBContextFactory et instancier une nouvelle instance pour chaque requête.

public class DbContextFactory
{
    public YourDbContext Create()
    {
        var options = new DbContextOptionsBuilder<YourDbContext>()
            .UseSqlServer(_connectionString)
            .Options;

        return new YourDbContext(options);
    }
}

Usage

public class Service
{
    private readonly DbContextFactory _dbContextFactory;

    public Service(DbContextFactory dbContextFactory) 
         => _dbContextFactory = dbContextFactory;

    public void Execute()
    {
        using (var context = _dbContextFactory.Create())
        {
            // use context
        }
    }
}    

Avec l'usine, vous n'avez plus besoin de vous inquiéter des slopes et de rendre votre code sans dépendances de base ASP.NET.
[.
[.____] Vous serez toujours confiant sur les données enregistrées lors de l'appelant .SaveChanges(), où avec Scoped DBContext, il existe des possibilités qu'une entité a été modifiée dans d'autres catégories.

0
Fabio