How to Instantiate a Dbcontext in Ef Core

How to instantiate a DbContext in EF Core

Note


At the time of writing the use of EF Core with the Dependency injection framework wasn't as known as it is now. This answers gives answer to the question from a DI perspective, which at the time, helped out OP.

The other answer provides you a conventional way to instantiate the DbContext using the new operator.



TL;DR, 3 options:

Option 1

Register the DbContext during application configuration:

public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
}

and use the DI framework to retrieve it:

public class SomeController : Controller
{
private readonly BlexzWebDb _db;

//the framework handles this
public SomeController(BlexzWebDb db)
{
_db = db;
}
}

Option 2

If you are looking for a design-time IdentityDbContext using IOptions<OperationalStoreOptions>, see: Add migration for ApiAuthorizationDbContext from another project - EF Core

Option 3

Or use the new operator and provide the details, see @Qamar Zaman's answer for details.



The long answer, and why DI is a treat

In EF Core it's common to pass some DbContextOptions to the constructor.

So in general, a constructor looks like this:

public BlexzWebDb(DbContextOptions<BlexzWebDb> options) : base(options)

As you can see there, there is no valid overload in the form of a parameter-less constructor:

Thus, this does not work:

using (var db = new BlexzWebDb())

Obviously, you can pass in an Option object in the constructor but there is an alternative. So,

Instead


.Net Core has IoC implemented in it's roots. Okay, this means; you don't create a context, you ask the framework to give you one, based on some rules you defined before.

Example: somewhere you will register your dbcontext, (Startup.cs):

//typical configuration part of .net core
public void ConfigureServices(IServiceCollection services)
{
//some mvc
services.AddMvc();

//hey, options!
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
//...etc

Now the registering part is done, you can retrieve your context from the framework. E.g.: inversion of control through a constructor in your controller:

public class SomeController : Controller
{
private readonly BlexzWebDb _db;

//the framework handles this
public SomeController(BlexzWebDb db)
{
_db = db;
}

//etc.


why?

So, why not just provide the arguments and new it?

There is nothing wrong with the use of new - there are a lot of scenario's in which it works best.

But, Inversion Of Control is considered to be a good practice. When doing asp dotnet core you're likely to use it quite often because most libraries provide extension methods to use it. If you are not familiar with it, and your research allow it; you should definitely give it a try.

Therefore, instead of providing "just a way to instantiate" the object, I'll try to get you onto this track - inline with the framework. It will save you some hassle afterwards. Besides, otherwise "use an activator's CreateInstance" would just be as valid as an answer ;-)

Some links:

  • MSDN Fundamentals
  • MSDN Dependency Injection
  • Wikipedia Inversion Of Control

Instantiate a DbContext in IntegrationTests

The context still needs to get the connection string and configuration while your default constructor bypasses all of that.

First get rid of the default constructor in your Db context

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

public DbSet<Employee> Employees { get; set; }
}

Next update the test to take advantage of the already provided configuration functionality

[Fact]
void TestMethod() {
//Arrange
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
optionsBuilder.UseSqlServer("connection string here");

using (var context = new MyContext(optionsBuilder.Options)) {
var service = new MyService(context);

//Act
var result = service.GetAll();//Error here

//Assert
Assert.True(result.Count() > 0);
}
}

Reference Configuring a DbContext: Configuring DbContextOptions

How to create a class library that can use any Ef Core DbContext

You can use a where condition on Method.

public class TranslateManager : ITranslateManager
{
private readonly ContextDb _contextDb;

public TranslateManager(ContextDb contextDb)
{
_contextDb = contextDb;
}

public async Task CreateTranslationAsync<T>(long langId) where T : class, ITranslate
{
// ToDo
}

public async Task<ITranslate> GetBestTranslationAsync<T>(long langId) where T : class, ITranslate
{
var dbSet = _contextDb.GetDbSet<T>();
return await dbSet.Where(x => x.LangId == langId).FirstOrDefaultAsync();
}
}

public interface ITranslate
{
public long Id { get; set; }
public long ParentId { get; set; }
public long LangId { get; set; }
}

public partial class SectionTranslation : ITranslate
{
public long Id { get; set; }
public long ParentId { get; set; }
public long LangId { get; set; }
public string SectionName { get; set; }
}

public partial class TemplateTranslation : ITranslate
{
public long Id { get; set; }
public long ParentId { get; set; }
public long LangId { get; set; }
public string TemplateName { get; set; }
}

public interface ITranslateManager
{
Task<T> GetBestTranslationAsync<T>(long langId) where T : class, ITranslate;
Task CreateTranslationAsync<T>(long langId) where T : class, ITranslate;
}

How to instantiate DBContext in second thread?

You should be able use a using statement everywhere you need a unique instance and instantiate a new context that will be disposed when it is done.

using (var newContext = new TerminalDbContext(new DbContextOptionsBuilder<TerminalDbContext>()
{
// Define options
}))
{
DoSomething();
}

Create SQL Database From DBContext EF Core

The fastest way was running these commands:

Add-Migration InitialCreate

and Then:

Update-Database



Related Topics



Leave a reply



Submit