0

Coming from a Java environment I'm having a few issues wrapping my head about the inheritable DBContext class. with Java EE I used to:

  1. Set up one or multiple DB Contexts (if separate clusters of entities where affected);
  2. Added the Context to respective DataAccessor classes that handled the query execution via DI;

Now with EF Core practically all samples I see create an instance of a MyDBContext by calling the default constructor:

 using (var db = new myContext()){...}

This raises a few questions for me:

  • With this Method each DataAccessor class that calls the constructor has its own instance of the Context. Wouldn't it be nicer to only ave one and use DI to inject it when needed?
  • How do I call the constructor if i didn't overload OnConfiguring(...) to pass the options, but instead used AddDbContext as a Service in Startup.cs? Now the overloaded constructor with the options expects them to be passed on each time the constructor is called.
  • Is having multiple DBContexts per application/Db even a good practise with EF Core?
2
  • A DbContext is a Unit-of-Work. It collects all changes and saves them only if SaveChanges is called. That's why all examples and tutorials use using, and you should too. Commented Oct 21, 2020 at 6:37
  • As for configuring, the examples show how to configure it from the outside, how to pass option, or if you use .NET Core DI, how to do that using AddDbContext with a builder action Commented Oct 21, 2020 at 6:39

1 Answer 1

2

Normally you would want single instance per request scope

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        // use options as you would use them in the .OnConfiguring
        options.UseSqlServer("your connectionString");
    );
}

If you use constructor injection in services, ASP.NET service provider will resolve db context as constructor parameter. All services that have db context this way will share same instance.

public class ServiceDependentOnContext
{
    private readonly ApplicationDbContext dbContext;

    public ServiceDependentOnContext(ApplicationDbContext dbContext)
    {
        this.dbContext = dbContext;
    }
}

Make sure you configure your service for dependency injection as well

// This method gets called by the runtime. Use this method to add services to the container.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer("your connectionString")
    );

    services.AddScoped<ServiceDependentOnContext>();
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks. With this and @Darem 's comment I was able to figure it out now; I Injected the DBContext into a repository used by the controller. But this raises the remaining question again: is it necessary/good practise to let the the DBContext implement multiple interfaces dependent on which responsibilities the different repos using it have? And, refering to Darem's comment: will I have threading issues with AddScoped or should I use transient?
transient is the same as if you were doing new DbContext every time. You won't have any threading issues with scoped lifetime, since you are not going to use more than 1 thread per request (unless intended by code). I don't understand the first question, why would you need multiple interfaces for different repos. If you need dynamic options for db context, you could configure it at runtime using IServiceProvider. see my answer at stackoverflow.com/a/64444899/7313094
scoped lifetime used to ensure all entities that were created/listed belong to the same DbContext.EntityTracker. so if you are doing stuff in different services, you can commit all changes at once with single DbContext.SaveChanges() invokation. which looks very like transaction behaviour - commit all or revert.
Presume I have three Repositories with different responsibilities. I would then let the single DBContext implement three distinct interfaces containing the required subset of methods to access the DB through the repo. The alternative would be to let the DBContext contain only one interface containing all methods used by all three repos. I see this might be a subjective question but I was wondering if there was a usual practice with ASP.NET.
this is up to you. I don't see point of adding interfaces to DbContext, all the methods you need are Set<T> and SaveChanges, so usually I end up inserting db context directly inside repositories/services/handlers
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.