web-dev-qa-db-fra.com

Que contient DbContextOptions lors de l’appel d’un nouveau DbContext?

Je n'utilise pas DI et je veux simplement appeler un DbContext depuis mon contrôleur. J'ai du mal à comprendre quelles devraient être les "options"?

ApplicationDbContext.cs

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{

    public DbSet<Gig> Gigs { get; set; }
    public DbSet<Genre> Genres { get; set; }


    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}

GigsController.cs

    public class GigsController : Controller
{
    private ApplicationDbContext _context;

    public GigsController()
    {
        _context = new ApplicationDbContext();
    }


    public IActionResult Create()
    {
        var viewModel = new GigFormViewModel
        {
            Genres = _context.Genres.ToList()
        };


        return View(viewModel);
    }
}

Le problème est lié à mon constructeur GigsController:

_context = new ApplicationDbContext();

Je me trompe parce que je dois passer quelque chose dans ApplicationDbContext. Aucun argument donné ne correspond au paramètre formel requis "options" de "ApplicationDbContext.ApplicationDbContext (DbContextOptions)". 

J'ai essayé de créer un constructeur par défaut dans ApplicationDbContext dérivé de base (), mais cela n'a pas fonctionné non plus.

Dans mon startup.cs, j'ai configuré le ApplicationDbContext

        public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddMvc();

        // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }
20
Reza

Si vous vraiment voulez créer le contexte manuellement, vous pouvez configurer comme ceci:

var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer(Configuration.GetConnectionStringSecureValue("DefaultConnection"));
_context = new ApplicationDbContext(optionsBuilder.Options); 

(La classe DbContextOptionsBuilder<ApplicationDbContext> correspond au type d'argument options dans services.AddDbContext<ApplicationDbContext>(options =>). Mais dans le contrôleur, vous n'avez pas accès à l'objet Configuration; vous devez donc l'exposer sous forme de champ statique dans Startup.cs ou utiliser un autre truc, ce qui est une mauvaise pratique.

Le meilleur moyen d’obtenir ApplicationDbContext est de le faire par DI:

public GigsController(ApplicationDbContext context)
{
    _context = context;
}

Le conteneur d’ID assurera l’instanciation et l’élimination de ApplicationDbContext. Notez que tout est correctement configuré dans Startup.cs:

services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

C'est la configuration de DI, alors pourquoi ne pas l'utiliser? 

Encore une remarque sur le constructeur par défaut de DbContext: Dans EF6, cela se faisait comme suit: public ApplicationDbContext(): base("DefaultConnection") {}. Ensuite, l'objet de base utilisera la classe statique System.Configuration.ConfigurationManager pour obtenir la chaîne de connexion nommée DefaultConnection à partir de web.config. Les nouveaux Asp.net Core et EF Core sont conçus pour être le plus découplés possible. Ils ne doivent donc pas dépendre de dépendances d'aucun système de configuration. Au lieu de cela, vous passez juste un objet DbContextOptions - la création de cet objet et sa configuration constituent un problème distinct.

33
qbik

Voici comment je le ferais:

public class GigsController : Controller
{
    private readonly IConfiguration _configuration;
    private string _connectionString;
    DbContextOptionsBuilder<ApplicationDbContext> _optionsBuilder;

    public GigsController (IConfiguration configuration)
    {
        _configuration = configuration;
        _optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
        _connectionString = _configuration.GetConnectionString("DefaultConnection");
        _optionsBuilder.UseSqlServer(_connectionString);
    }

    public IActionResult Index()
    {
        using(ApplicationDbContext _context = new ApplicationDbContext(_optionsBuilder.Options))
        {
             // .....Do something here
        }
    }
}

Récemment, je migrais un très grand ensemble de données vers une base de données (environ 10 millions de dollars) et une instance de contexte consommerait toute ma mémoire. J'ai donc dû créer une nouvelle instance de contexte et disposer de l'ancienne après un certain seuil pour libérer de la mémoire.

Ce n'est pas une solution élégante mais a fonctionné pour moi.

1
Aven