web-dev-qa-db-fra.com

Le DbContext de type ne peut pas être regroupé car il n'a pas un seul constructeur public acceptant un seul paramètre de type DbContextOptions

J'essaie de mettre à niveau notre application .Net Core actuelle de 1.1 à 2.0 et j'obtiens cette erreur d'exécution: "Le DbContext de type 'CoreContext' ne peut pas être mis en commun car il n'a pas un seul constructeur public acceptant un seul paramètre de type DbContextOptions" .

Cela est dû à l'utilisation de la nouvelle fonction IServiceCollection.AddDbContextPool <>. Lorsque j'utilise IServiceCollection.AddDbContext <> cela fonctionne toujours.

Cette application est DB-First, donc je génère tous nos contextes en utilisant 'Scaffold-DbContext'. Pour cette raison, et la nécessité d'injecter d'autres services, j'ai une extension sur chaque contexte comme celui-ci:

public partial class CoreContext
{
    public CoreContext(
        DbContextOptions<CoreContext> options,
        IUserService userService,
        IAuditRepository auditRepository
        ) : base(options) {...}
}

Chaque fois que j'exécute Scaffold-DbContext, je supprime simplement le constructeur généré automatiquement de CoreContext, mais même si je le mets dedans, j'obtiens toujours cette erreur.

public partial class CoreContext : DbContext
{
    public CoreContext(DbContextOptions<CoreContext> options) : base(options) {}
}

J'ai déjà mis à jour Program.cs vers le nouveau style:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();
}

Et le Startup.cs est assez simple:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    ...
    services.AddDbContextPool<CoreContext>(options => options.UseSqlServer(absConnectionString));
    ...
}

J'utilise Autofac pour DI si cela aide. Pour l'instant, je reviendrai par défaut à l'alternative non-Pooling, mais ce serait bien de profiter de cette fonctionnalité.

10
Jeff Keslinke

Lors de l'utilisation de DbContext Pooling, votre propre état (par exemple, les champs privés) dans votre classe DbContext dérivée sera conservé. Ce qui signifie que la durée de vie de vos services est désormais singleton. C'est pourquoi vous ne devriez pas avoir d'autres services injectés ici. Mais il est possible d'interroger les services requis de cette façon: nous devons d'abord utiliser la méthode UseInternalServiceProvider sur DbContextOptionsBuilder pour indiquer à EF quel fournisseur de services utiliser pour ses services. Ce fournisseur de services doit avoir configuré tous les services pour EF et tous les fournisseurs. Nous devons donc enregistrer les services EF manuellement:

services.AddEntityFrameworkSqlServer();

Et introduisez ensuite le fournisseur de services de l'application qui inclut désormais les services EF:

services.AddDbContextPool<ApplicationDbContext>((serviceProvider, optionsBuilder) =>
{
   optionsBuilder.UseSqlServer("...");
   optionsBuilder.UseInternalServiceProvider(serviceProvider);
});

Après cela, définissez ces espaces de noms:

using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;

Et maintenant, vous pouvez accéder aux services enregistrés dans l'application au sein de la classe ApplicationDbContext à l'aide des méthodes suivantes

var siteSettings = this.GetService<IOptionsSnapshot<SiteSettings>>();

Ou

var siteSettings = this.GetInfrastructure().GetRequiredService<IOptionsSnapshot<SiteSettings>>();

this est l'instance actuelle de DbContext.

18
VahidN

"car il n'a pas un seul constructeur public acceptant un seul paramètre de type DbContextOptions"

Si vous avez des constructeurs publics en dehors de celui qui accepte DbContextOptions, vous devez les supprimer ou les rendre non publics afin d'utiliser le regroupement de contextes.

En outre, il existe des restrictions sur ce qui peut être fait en remplaçant la méthode OnConfiguring. Ceci est référencé dans la documentation ici mais il n'est pas explicite sur ce que sont ces restrictions: https://docs.Microsoft.com/en-us/ef/core/what-is-new/index#dbcontext -Covoiturage

3
Rob

Supprimez le constructeur par défaut dans la classe DbContext, cela a fonctionné pour moi

3
C.Ikongo

ce problème est principalement rencontré lorsque vous "Scaffold-Dbcontext" et deux constructeurs sont générés.

Solutions simples: 1. AddDbContextPool: Si vous souhaitez utiliser AddDbContextPool, supprimez votre constructeur vide et conservez celui avec le DbContextOptionsBuilder. Notez que dans ce cas, vous devrez peut-être fournir les options, comme suggéré dans les articles précédents.

  1. AddDbContext: Avec AddDbContext, vous pouvez avoir les deux constructeurs/surcharges

Remarque: AddDbContextPool est préféré pour performances raisons!

2
Abdul Basit

essayez d'utiliser AddDbContext au lieu de AddDbContextPool. Cela m'a aidé dans la même situation. services.AddDbContext<CoreContext>(options => options.UseSqlServer(absConnectionString));

0
Kazantsev