Reputation: 2761
...Maybe using TFactory in AddDbContextFactory<TContext, TFactory>
in EF Core extensions?
I've only seen AddDbContextFactory examples being used with just the TContext generic. They're always very explicit to say you have to use a using statement.
In similar situations (when I useClass in Angular or AddScoped in .NET Core), I make the variable I want to see in a constructor the first generic argument and the second generic argument what actually gets injected. You know, like:
services.AddScoped<IService, RealService>();
Obviously, this isn't the case with
services.AddDbContextFactory<ADbContextIHaveBeenInjecting, AFactoryThatWillReturnADbContextIHaveBeenInjecting>();
I was hoping this would eliminate the need to do the whole using thing.
Is there another way I can do this without having to re-write every injected DbContext to conform with their prescribed:
public void DoSomething()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
As I said, my hope was to use something like this for the factory:
public class MyDbContextFactory : IDbContextFactory<MyDbContext>
{
public MyDbContextFactory(DbContextOptions options)
{
}
public MyDbContext CreateDbContext()
{
var ProviderName = GetProviderName();
switch (ProviderName)
{
case "System.Data.SqlClient":
return new SqlServerDbContext(new DbContextOptionsBuilder<SqlServerDbContext>().UseSqlServer(ConnectionString).Options);
case "Npgsql":
return new PostgreSqlDbContext(new DbContextOptionsBuilder<PostgreSqlDbContext>().UseNpgsql(ConnectionString).Options);
default:
throw new NullReferenceException("Missing provider name for DbContext. Should be Npgsql or System.Data.SqlClient");
}
}
}
Then, set it up in Startup.cs ConfigureServices like:
services.AddDbContextFactory<MyDbContext, MyDbContextFactory>();
So I could inject in a class like this:
public class MyController : BaseApiController
{
private readonly MyDbContext _myDbContext;
public MyController(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
[HttpGet("GetACount")]
public IActionResult GetACount()
{
var count = _myDbContext.MyRecord.Count();
return Ok(count);
}
...
Is there a way to do this using the AddDbContextFactory? What is TFactory actually for? Is there another way to do this?
Upvotes: 2
Views: 10493
Reputation: 89191
DbContextFactory is specifically intended to require you to manage the lifecycle of your DbContext, because Blazor server apps don't use a Scope-per-Http request like ASP.NET Core does, so a Scoped DbContext won't work.
If you want a Scoped DbContext just use .AddDbContext
intead of .AddDbContextFactory
.
If you have registered a DbContextFactory but still want to inject a scoped DbContext directly in your services, then register it like this:
services.AddScoped<MyDbContext>(sp =>
{
var cf = sp.GetRequiredService<IDbContextFactory<MyDbContext>>();
var db = cf.CreateDbContext();
return db;
});
Upvotes: 2
Reputation: 4243
Dependency inject the concrete class. create a factory to select the subclass by type. Create a parent class with a private DbContext _dbContext. Inherit the subclass from the parent class and call the parent class constructor with :base(dbContext) of the subclass. The parent class can now access in its methods the subclass context. The subclass can share the methods of the parent class for (add, select, update, and deleting by set the data context of the subclass). the subclass will dependency inject the specific dbcontext in its constructor and set the parent class dbcontext variable in its constructor. the subclass repository class can then access the base class methods within its body.
in startup define the subclass repository pattern
in public void ConfigureServices(IServiceCollection services)
var connectionString = Configuration.GetConnectionString("ABCContext_DbCoreConnectionString");
services.AddDbContext<ABCContext>(options1 => options1.UseSqlServer(connectionString));
services.AddTransient<IRepositoryMySubclass, RepositoryMySubclass>();
sub class
public RepositorySubclass(ABCContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
}
Upvotes: 1