Home > front end >  EF Core 6/7 - Accessing derived DbContext
EF Core 6/7 - Accessing derived DbContext

Time:01-11

I have a base library which includes some basic entities (logs, settings, ...) in a DbContext class. In my specific project I am inheriting the Context from this class and do the project specific stuff.

Base Context

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

Project Specific Context

public class ProjectContext: BaseContext {
    public ProjectContext(DbContextOptions<BaseContext> options)
            : base(options)
    {
            
    }

    public ProjectContext(DbContextOptions options)
            : base(options)
    {
            
    }
}

Context will be added in Startup:

services.AddDbContext<Context>(options =>
                {
                    if (Helpers.IsDevelopment())
                    {
                        options.EnableSensitiveDataLogging();
                        options.EnableDetailedErrors();
                    }

                    options.UseNpgsql(Configuration.GetConnectionString("Context"), b =>
                    {
                        b.MigrationsAssembly("App.Project.Specific");
                        b.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
                        b.EnableRetryOnFailure(5);
                    });
                }
            );

So some services and controlers implemented in the base library work with BaseContext, which is a child of Context.

public AssetsService(BaseContext db,...

So this results in the following error message:

Unable to resolve service for type 'App.Shared.DataModel.BaseContext' while attempting to activate 'App.Shared.Services.AssetsService

So how to inject the contexts correctly to get access from both ways?

CodePudding user response:

A DbContext is a multi-entity Repository and Unit-of-Work. It makes little sense to have a "base" repository and no sense to register the base instead of concrete repositories.

Furthermore, the DI container can't guess by itself which concrete service to create when only a base class is registered. .NET can't guess which specific Repository classes like AssetsService or CustomersService want. If both SalesContext and MarketingContext inherit from some base Context class, why not send MarketingContext to CustomersService and SalesContext to WarehouseService?

DI registration

For starters, all the DbContext types that are going to be used need to be registered. If a service expects a BaseContext, then BaseContext should be registered. Same with ProjectContext, TimeSheetContext, CustomerContext etc. Registering a base class doesn't register its derived classes.

Common registration and configuration

It seems that the real question is how to register multiple DbContexts using the same code. This can be done with an extension method that accepts a DbContext type parameter and calls AddDbContext :

public static IServiceCollection AddMyContext<T>(
    this IServiceCollection services,
    IConfiguration configuration) where T:DbContext
{
    services.AddDbContext<T>(options =>
            {
                if (Helpers.IsDevelopment())
                {
                    options.EnableSensitiveDataLogging();
                    options.EnableDetailedErrors();
                }

                options.UseNpgsql(configuration.GetConnectionString("Context"), b =>
                {
                    b.MigrationsAssembly("App.Project.Specific");
                    b.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
                    b.EnableRetryOnFailure(5);
                });
            }
        );
    return services;
}

In the application's startup, call AddMyContext instead of AddDbContext.

  • Related