Что происходит с 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; }
}