Pytanie Co się dzieje z DbContextOptions podczas wywoływania nowego DbContext?


Nie używam DI i po prostu chcę wywołać DbContext z mojego kontrolera. Walczę, aby dowiedzieć się, jakie powinny być "opcje"?

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);
    }
}

Ten problem występuje w moim konstruktorze GigsController:

_context = new ApplicationDbContext();

Błąd, ponieważ muszę przekazać coś do ApplicationDbContext. Nie ma żadnego argumentu, który odpowiada wymaganemu parametrowi formalnemu "opcje" w "ApplicationDbContext.ApplicationDbContext (DbContextOptions)"

Próbowałem utworzyć domyślny konstruktor w ApplicationDbContext pochodzący z base (), ale to też nie działało.

W moim pliku startup.cs skonfigurowałem 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>();
    }

14
2017-07-17 01:11


pochodzenie


Którą wersję Microsoft.AspNet.Identity.EntityFramework używasz? - Stephen Zeng
najnowsza wersja 1.0 "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0" - Reza
Czy próbowałeś dodać? public ApplicationDbContext(): base("DefaultConnection") { } ? - Stephen Zeng
tak, baza akceptuje tylko wartości DbContextOptions. Znalazłem obejście, zastępując OnConfiguring i dodając domyślny konstruktor, ale uważam, że to nie jest eleganckie rozwiązanie, ponieważ muszę dwukrotnie odsłonić ciąg połączenia ... raz w startup.cs i raz w klasie Context - Reza


Odpowiedzi:


Jeśli ty naprawdę chcesz ręcznie utworzyć kontekst, a następnie możesz skonfigurować to tak:

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

(The DbContextOptionsBuilder<ApplicationDbContext> klasa to typ options argument w services.AddDbContext<ApplicationDbContext>(options =>). Ale w kontrolerze nie masz dostępu Configuration obiekt, więc musiałbyś wystawić go jako pole statyczne Startup.cs lub użyj jakiejś innej sztuczki, która jest złą praktyką.

Najlepszy sposób na uzyskanie ApplicationDbContext jest przejście przez DI:

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

Kontener DI zajmie się tworzeniem instancji i rozporządzania z ApplicationDbContext. Zwróć uwagę, że wszystko jest poprawnie skonfigurowane Startup.cs:

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

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

To konfiguracja DI, więc dlaczego po prostu go nie używać?

Jeszcze jedna uwaga dotycząca domyślnego konstruktora DbContext: W EF6 zostało to zrobione w następujący sposób: public ApplicationDbContext(): base("DefaultConnection") {}. Wtedy użyłby obiekt bazowy System.Configuration.ConfigurationManager klasa statyczna, aby uzyskać nazwany ciąg połączenia DefaultConnection od web.config. Nowe Asp.net Core i EF Core zaprojektowano tak, aby były jak najmniej rozdzielone, więc nie powinny być zależne od jakiegokolwiek systemu konfiguracji. Zamiast tego po prostu przekazujesz a DbContextOptions obiekt - tworzenie tego obiektu i jego konfiguracja jest osobną sprawą.


23
2017-07-17 05:07



Wkurzającą częścią tego wszystkiego jest "i usuwanie części ApplicationDbContext". Na przykład chcesz użyć kontekstu db, który zostanie usunięty po cyklu żądania / odpowiedzi. - Ronnie Overby