Что происходит с DbContextOptions при вызове нового DbContext?

Я не использую DI и просто хочу вызвать DbContext из моего контроллера. Я изо всех сил пытаюсь выяснить, какие "варианты" должны быть?

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

Проблема возникает в моем конструкторе GigsController:

_context = new ApplicationDbContext();

Я ошибаюсь, потому что мне нужно передать что-то в ApplicationDbContext. Нет аргументов, которые соответствуют требуемому формальному параметру "options" для ApplicationDbContext.ApplicationDbContext(DbContextOptions)

Я попытался создать конструктор по умолчанию в ApplicationDbContext, полученный из base(), но это тоже не сработало.

В моем startup.cs я настроил 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>();
    }

Ответ 1

Если вы действительно хотите создать контекст вручную, то вы можете настроить его следующим образом:

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

(Класс DbContextOptionsBuilder<ApplicationDbContext> является типом аргумента options в services.AddDbContext<ApplicationDbContext>(options =>). Но в контроллере у вас нет доступа к объекту Configuration, поэтому вам придется представить его как статическое поле в Startup.cs или используйте какой-то другой трюк, что является плохой практикой.

Лучший способ получить ApplicationDbContext - получить его через DI:

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

Контейнер DI позаботится о создании и удалении ApplicationDbContext. Обратите внимание, что у вас все правильно настроено в Startup.cs:

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

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

Это настройка DI, так почему бы просто не использовать его?

Еще одно замечание о конструкторе по умолчанию для DbContext: в EF6 это было сделано так: public ApplicationDbContext(): base("DefaultConnection") {}. Затем базовый объект будет использовать статический класс System.Configuration.ConfigurationManager для получения строки подключения с именем DefaultConnection из web.config. Новые ядра Asp.net и EF Core спроектированы таким образом, чтобы их можно было максимально разъединить, поэтому они не должны зависеть от какой-либо системы конфигурации. Вместо этого вы просто передаете объект DbContextOptions - создание этого объекта и его настройка являются отдельной задачей.

Ответ 2

Вот как я бы это сделал:

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

Недавно я перенес очень большой набор данных в базу данных (около 10 миллионов), и один экземпляр контекста быстро поглотит всю мою память. Таким образом, мне пришлось создать новый экземпляр Context и утилизировать старый после определенного порога, чтобы освободить память.

Это не элегантное решение, но сработало для меня.

Ответ 3

 public class PaymentDetailContext:DbContext //inherit this class from DB context from entity framework core DB Context 
    {
        public PaymentDetailContext(DbContextOptions<PaymentDetailContext> options):base(options) 
            //CONSTRUCTOR-------------PARAMETER----------TYPE----------------NAME---PARENT CONTSTRUCTOR
        {

        }
        public DbSet<PaymentDetail> PaymentDetails { get; set; }
    }