I am implementing Entity Framework Code-First in ASP.NET Core-6 Web API. I am using IdentityDbContext, and I have this code:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long, IdentityUserClaim<long>, ApplicationUserRole, IdentityUserLogin<long>, IdentityRoleClaim<long>, IdentityUserToken<long>>
{
private readonly ICurrentUserService _currentUser;
private readonly IDateTime _dateTime;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, ICurrentUserService currentUser, IDateTime dateTime) : base(options)
{
_currentUser = currentUser;
_dateTime = dateTime;
}
public DbSet<Transaction> Transactions { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<ApplicationRole> ApplicationRoles { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
base.OnModelCreating(builder);
builder.ApplyConfiguration(new TransactionConfigurations());
builder.ApplyConfiguration(new ApplicationUserConfigurations());
builder.ApplyConfiguration(new ApplicationUserRoleConfigurations());
builder.ApplyConfiguration(new ApplicationRoleConfigurations());
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
foreach (var item in ChangeTracker.Entries<AuditableEntity>())
{
switch (item.State)
{
case EntityState.Modified:
item.Entity.LastModifiedBy = _currentUser.UserName;
item.Entity.LastModifiedAt = _dateTime.Now;
break;
case EntityState.Added:
item.Entity.CreatedBy = _currentUser.UserName;
item.Entity.CreatedAt = _dateTime.Now;
break;
case EntityState.Deleted:
item.Entity.DeletedBy = _currentUser.UserName;
item.Entity.DeletedAt = _dateTime.Now;
item.Entity.IsDeleted = true;
break;
default:
break;
}
}
return await base.SaveChangesAsync(cancellationToken);
}
}
When I want to create Migration using Add-Migration InitialCreate -OutputDir Persistence\Migrations
I got this error:
The DbContext of type 'ApplicationDbContext' cannot be pooled because it does not have a public constructor accepting a single parameter of type DbContextOptions or has more than one constructor.
How do I get it resolved?
Thanks
CodePudding user response:
When you use context pooling, usually via AddDbContextPool
, your context can only have a single constructor, and it must only take a single parameter of type DbContextOptions<TContext>
. Of course, you need other objects but there is a solution. An EF Core DbContext has tight integration with dependency injection, so you can do this in your constructor instead:
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
_currentUser = this.GetService<ICurrentUserService>();
_dateTime = this.GetService<IDateTime>();
}
CodePudding user response:
Your problem is caused by wanting to inject services into the DbContext, which isn't that terrific of an idea.
Wrap it around: create a handler to handle the DbContext.SavingChanges event and update your entities in there.
See Callback on SaveChanges in EFCore? for an implementation thereof.
Also, assuming Transactions
inherits AuditableEntity
, I'm not sure ChangeTracker.Entries<AuditableEntity>()
will do what you expect it to.